pccard.c revision 74636
166200Simp/* $NetBSD: pcmcia.c,v 1.23 2000/07/28 19:17:02 drochner Exp $ */ 252506Simp/* $FreeBSD: head/sys/dev/pccard/pccard.c 74636 2001-03-22 06:00:07Z 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 5867333Simp#define PRVERBOSE(arg) printf arg 5967333Simp#define DEVPRVERBOSE(arg) device_printf arg 6052506Simp#else 6152506Simp#define DPRINTF(arg) 6255500Simp#define DEVPRINTF(arg) 6367333Simp#define PRVERBOSE(arg) if (bootverbose) printf arg 6467333Simp#define DEVPRVERBOSE(arg) if (bootverbose) device_printf arg 6552506Simp#endif 6652506Simp 6752506Simp#ifdef PCCARDVERBOSE 6852506Simpint pccard_verbose = 1; 6952506Simp#else 7052506Simpint pccard_verbose = 0; 7152506Simp#endif 7252506Simp 7354250Simpint pccard_print(void *, const char *); 7452506Simp 7552506Simpint 7674632Simppccard_ccr_read(struct pccard_function *pf, int ccr) 7752506Simp{ 7852506Simp return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh, 7952506Simp pf->pf_ccr_offset + ccr)); 8052506Simp} 8152506Simp 8252506Simpvoid 8374632Simppccard_ccr_write(struct pccard_function *pf, int ccr, int val) 8452506Simp{ 8552506Simp if ((pf->ccr_mask) & (1 << (ccr / 2))) { 8652506Simp bus_space_write_1(pf->pf_ccrt, pf->pf_ccrh, 8752506Simp pf->pf_ccr_offset + ccr, val); 8852506Simp } 8952506Simp} 9052506Simp 9159193Simpstatic int 9259193Simppccard_attach_card(device_t dev) 9352506Simp{ 9464850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 9552506Simp struct pccard_function *pf; 9665917Simp struct pccard_ivar *ivar; 9761788Simp device_t child; 9852506Simp int attached; 9952506Simp 10070715Sjon sc->intr_handler_count = 0; 10152506Simp /* 10252506Simp * this is here so that when socket_enable calls gettype, trt happens 10352506Simp */ 10452506Simp STAILQ_INIT(&sc->card.pf_head); 10552506Simp 10655500Simp DEVPRINTF((dev, "chip_socket_enable\n")); 10755500Simp POWER_ENABLE_SOCKET(device_get_parent(dev), dev); 10852506Simp 10955500Simp DEVPRINTF((dev, "read_cis\n")); 11052506Simp pccard_read_cis(sc); 11152506Simp 11255500Simp DEVPRINTF((dev, "check_cis_quirks\n")); 11352506Simp pccard_check_cis_quirks(dev); 11452506Simp 11552506Simp /* 11652506Simp * bail now if the card has no functions, or if there was an error in 11752506Simp * the cis. 11852506Simp */ 11952506Simp 12070715Sjon if (sc->card.error) { 12170715Sjon device_printf (dev, "CARD ERROR!\n"); 12252506Simp return (1); 12370715Sjon } 12470715Sjon if (STAILQ_EMPTY(&sc->card.pf_head)) { 12570715Sjon device_printf (dev, "Card has no functions!\n"); 12652506Simp return (1); 12770715Sjon } 12852506Simp 12961788Simp if (1) 13052506Simp pccard_print_cis(dev); 13152506Simp 13252506Simp attached = 0; 13352506Simp 13455500Simp DEVPRINTF((dev, "functions scanning\n")); 13552506Simp STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 13652506Simp if (STAILQ_EMPTY(&pf->cfe_head)) 13752506Simp continue; 13852506Simp 13952506Simp pf->sc = sc; 14052506Simp pf->cfe = NULL; 14164927Simp pf->dev = NULL; 14252506Simp } 14365098Simp#if 0 14464850Simp DEVPRINTF((dev, "chip_socket_disable\n")); 14564850Simp POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 14665098Simp#endif 14752506Simp STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 14852506Simp if (STAILQ_EMPTY(&pf->cfe_head)) 14952506Simp continue; 15061788Simp /* 15161788Simp * In NetBSD, the drivers are responsible for activating 15261788Simp * each function of a card. I think that in FreeBSD we 15361788Simp * want to activate them enough for the usual bus_*_resource 15461788Simp * routines will do the right thing. This many mean a 15561788Simp * departure from the current NetBSD model. 15661788Simp * 15761788Simp * This could get really ugly for multifunction cards. But 15861788Simp * it might also just fall out of the FreeBSD resource model. 15961788Simp * 16061788Simp */ 16167897Sdwmalone ivar = malloc(sizeof(struct pccard_ivar), M_DEVBUF, 16267897Sdwmalone M_WAITOK | M_ZERO); 16361788Simp child = device_add_child(dev, NULL, -1); 16465917Simp device_set_ivars(child, ivar); 16566847Simp ivar->fcn = pf; 16667187Simp pf->dev = child; 16767167Simp /* 16867167Simp * XXX We might want to move the next two lines into 16967167Simp * XXX the pccard interface layer. For the moment, this 17067167Simp * XXX is OK, but some drivers want to pick the config 17167167Simp * XXX entry to use as well as some address tweaks (mostly 17267167Simp * XXX due to bugs in decode logic that makes some 17367167Simp * XXX addresses illegal or broken). 17467167Simp */ 17565917Simp pccard_function_init(pf); 17667333Simp if (pccard_function_enable(pf) == 0 && 17767333Simp device_probe_and_attach(child) == 0) { 17852506Simp attached++; 17952506Simp 18055500Simp DEVPRINTF((sc->dev, "function %d CCR at %d " 18167167Simp "offset %x: %x %x %x %x, %x %x %x %x, %x\n", 18267167Simp pf->number, pf->pf_ccr_window, pf->pf_ccr_offset, 18367167Simp pccard_ccr_read(pf, 0x00), 18452506Simp pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04), 18552506Simp pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A), 18652506Simp pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E), 18752506Simp pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12))); 18867167Simp } else { 18967167Simp device_delete_child(dev, child); 19052506Simp } 19152506Simp } 19274632Simp return (0); 19352506Simp} 19452506Simp 19559193Simpstatic int 19659193Simppccard_detach_card(device_t dev, int flags) 19752506Simp{ 19864850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 19952506Simp struct pccard_function *pf; 20052506Simp 20152506Simp /* 20252506Simp * We are running on either the PCCARD socket's event thread 20352506Simp * or in user context detaching a device by user request. 20452506Simp */ 20552506Simp STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 20652506Simp if (STAILQ_FIRST(&pf->cfe_head) == NULL) 20752506Simp continue; 20861788Simp 20961788Simp pccard_function_disable(pf); 21070766Speter /* 21170766Speter * XXX must also actually delete resources created by 21270766Speter * pccard_function_init() 21370766Speter */ 21464927Simp if (pf->dev) 21564927Simp device_delete_child(dev, pf->dev); 21652506Simp } 21774632Simp return (0); 21852506Simp} 21952506Simp 22066200Simpconst struct pccard_product * 22166200Simppccard_product_lookup(device_t dev, const struct pccard_product *tab, 22266200Simp size_t ent_size, pccard_product_match_fn matchfn) 22366200Simp{ 22466200Simp const struct pccard_product *ent; 22566200Simp int matches; 22666200Simp u_int32_t fcn; 22766200Simp u_int32_t vendor; 22866200Simp u_int32_t prod; 22966200Simp char *vendorstr; 23066200Simp char *prodstr; 23166200Simp 23266200Simp#ifdef DIAGNOSTIC 23366200Simp if (sizeof *ent > ent_size) 23470715Sjon panic("pccard_product_lookup: bogus ent_size %ld", 23566200Simp (long) ent_size); 23666200Simp#endif 23766200Simp if (pccard_get_vendor(dev, &vendor)) 23866200Simp return (NULL); 23966200Simp if (pccard_get_product(dev, &prod)) 24066200Simp return (NULL); 24166200Simp if (pccard_get_function_number(dev, &fcn)) 24266200Simp return (NULL); 24366200Simp if (pccard_get_vendor_str(dev, &vendorstr)) 24466200Simp return (NULL); 24566200Simp if (pccard_get_product_str(dev, &prodstr)) 24666200Simp return (NULL); 24770715Sjon for (ent = tab; ent->pp_name != NULL; 24866200Simp ent = (const struct pccard_product *) 24966200Simp ((const char *) ent + ent_size)) { 25066200Simp matches = 1; 25166200Simp if (matches && ent->pp_vendor != PCCARD_VENDOR_ANY && 25266200Simp vendor != ent->pp_vendor) 25366200Simp matches = 0; 25466200Simp if (matches && ent->pp_product != PCCARD_PRODUCT_ANY && 25566200Simp prod != ent->pp_product) 25666200Simp matches = 0; 25766200Simp if (matches && fcn != ent->pp_expfunc) 25866200Simp matches = 0; 25971322Simp if (matches && ent->pp_cis[0] && 26071322Simp strcmp(ent->pp_cis[0], vendorstr) != 0) 26166200Simp matches = 0; 26271322Simp if (matches && ent->pp_cis[1] && 26371322Simp strcmp(ent->pp_cis[1], prodstr) != 0) 26466200Simp matches = 0; 26571322Simp /* XXX need to match cis[2] and cis[3] also XXX */ 26666200Simp if (matchfn != NULL) 26766200Simp matches = (*matchfn)(dev, ent, matches); 26866200Simp if (matches) 26966200Simp return (ent); 27066200Simp } 27166200Simp return (NULL); 27266200Simp} 27366200Simp 27470715Sjonstatic int 27559193Simppccard_card_gettype(device_t dev, int *type) 27652506Simp{ 27764850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 27852506Simp struct pccard_function *pf; 27952506Simp 28052506Simp /* 28152506Simp * set the iftype to memory if this card has no functions (not yet 28252506Simp * probed), or only one function, and that is not initialized yet or 28352506Simp * that is memory. 28452506Simp */ 28552506Simp pf = STAILQ_FIRST(&sc->card.pf_head); 28652506Simp if (pf == NULL || 28752506Simp (STAILQ_NEXT(pf, pf_list) == NULL && 28852506Simp (pf->cfe == NULL || pf->cfe->iftype == PCCARD_IFTYPE_MEMORY))) 28959193Simp *type = PCCARD_IFTYPE_MEMORY; 29052506Simp else 29159193Simp *type = PCCARD_IFTYPE_IO; 29274632Simp return (0); 29352506Simp} 29452506Simp 29552506Simp/* 29652506Simp * Initialize a PCCARD function. May be called as long as the function is 29752506Simp * disabled. 29852506Simp */ 29952506Simpvoid 30070715Sjonpccard_function_init(struct pccard_function *pf) 30152506Simp{ 30265917Simp struct pccard_config_entry *cfe; 30367187Simp int i; 30467242Simp struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); 30567242Simp struct resource_list *rl = &devi->resources; 30670762Simp struct resource_list_entry *rle; 30767242Simp struct resource *r = 0; 30867242Simp device_t bus; 30967424Simp int start; 31067424Simp int end; 31165917Simp 31270715Sjon if (pf->pf_flags & PFF_ENABLED) { 31370715Sjon printf("pccard_function_init: function is enabled"); 31470715Sjon return; 31570715Sjon } 31667242Simp bus = device_get_parent(pf->dev); 31752506Simp /* Remember which configuration entry we are using. */ 31872012Sphk STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) { 31967187Simp for (i = 0; i < cfe->num_iospace; i++) 32067187Simp cfe->iores[i] = NULL; 32167187Simp cfe->irqres = NULL; 32267187Simp for (i = 0; i < cfe->num_iospace; i++) { 32367424Simp start = cfe->iospace[i].start; 32467424Simp if (start) 32567424Simp end = start + cfe->iospace[i].length - 1; 32667424Simp else 32767424Simp end = ~0; 32867187Simp cfe->iorid[i] = i; 32967242Simp r = cfe->iores[i] = bus_alloc_resource(bus, 33067424Simp SYS_RES_IOPORT, &cfe->iorid[i], start, end, 33170715Sjon cfe->iospace[i].length, 33267424Simp rman_make_alignment_flags(cfe->iospace[i].length)); 33367187Simp if (cfe->iores[i] == 0) 33467187Simp goto not_this_one; 33567242Simp resource_list_add(rl, SYS_RES_IOPORT, cfe->iorid[i], 33667242Simp rman_get_start(r), rman_get_end(r), 33767242Simp cfe->iospace[i].length); 33870715Sjon { 33970762Simp rle = resource_list_find(rl, SYS_RES_IOPORT, 34070762Simp cfe->iorid[i]); 34170715Sjon rle->res = r; 34270715Sjon } 34367187Simp } 34467187Simp if (cfe->num_memspace > 0) { 34567187Simp goto not_this_one; 34667187Simp } 34767187Simp if (cfe->irqmask) { 34867187Simp cfe->irqrid = 0; 34967399Simp r = cfe->irqres = bus_alloc_resource(bus, SYS_RES_IRQ, 35067424Simp &cfe->irqrid, 0, ~0, 1, 0); 35167187Simp if (cfe->irqres == 0) 35267187Simp goto not_this_one; 35367242Simp resource_list_add(rl, SYS_RES_IRQ, cfe->irqrid, 35467242Simp rman_get_start(r), rman_get_end(r), 1); 35570715Sjon { 35670762Simp rle = resource_list_find(rl, SYS_RES_IRQ, 35770762Simp cfe->irqrid); 35870715Sjon rle->res = r; 35970715Sjon } 36067187Simp } 36167187Simp /* XXX Don't know how to deal with maxtwins */ 36267187Simp /* If we get to here, we've allocated all we need */ 36367167Simp pf->cfe = cfe; 36467187Simp break; 36567187Simp not_this_one:; 36667424Simp DEVPRVERBOSE((bus, "Allocation failed for cfe %d\n", 36767424Simp cfe->number)); 36867333Simp /* 36967333Simp * Release resources that we partially allocated 37067333Simp * from this config entry. 37167333Simp */ 37267187Simp for (i = 0; i < cfe->num_iospace; i++) { 37367242Simp resource_list_delete(rl, SYS_RES_IOPORT, i); 37467187Simp if (cfe->iores[i]) 37570715Sjon bus_release_resource(bus, SYS_RES_IOPORT, 37667187Simp cfe->iorid[i], cfe->iores[i]); 37767187Simp cfe->iores[i] = NULL; 37867187Simp } 37967187Simp if (cfe->irqmask && cfe->irqres) { 38067242Simp resource_list_delete(rl, SYS_RES_IRQ, cfe->irqrid); 38167242Simp bus_release_resource(bus, SYS_RES_IRQ, 38267187Simp cfe->irqrid, cfe->irqres); 38367187Simp cfe->irqres = NULL; 38467187Simp } 38567167Simp } 38652506Simp} 38752506Simp 38852506Simp/* Enable a PCCARD function */ 38952506Simpint 39055720Simppccard_function_enable(struct pccard_function *pf) 39152506Simp{ 39252506Simp struct pccard_function *tmp; 39352506Simp int reg; 39455720Simp device_t dev = pf->sc->dev; 39570746Simp 39667333Simp if (pf->cfe == NULL) { 39767333Simp DEVPRVERBOSE((dev, "No config entry could be allocated.\n")); 39874632Simp return (ENOMEM); 39967333Simp } 40052506Simp 40152506Simp /* 40252506Simp * Increase the reference count on the socket, enabling power, if 40352506Simp * necessary. 40452506Simp */ 40552506Simp if (pf->sc->sc_enabled_count++ == 0) 40655720Simp POWER_ENABLE_SOCKET(device_get_parent(dev), dev); 40755720Simp DEVPRINTF((dev, "++enabled_count = %d\n", pf->sc->sc_enabled_count)); 40852506Simp 40952506Simp if (pf->pf_flags & PFF_ENABLED) { 41052506Simp /* 41152506Simp * Don't do anything if we're already enabled. 41252506Simp */ 41352506Simp return (0); 41452506Simp } 41552506Simp 41652506Simp /* 41752506Simp * it's possible for different functions' CCRs to be in the same 41852506Simp * underlying page. Check for that. 41952506Simp */ 42052506Simp STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 42152506Simp if ((tmp->pf_flags & PFF_ENABLED) && 42252506Simp (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 42352506Simp ((pf->ccr_base + PCCARD_CCR_SIZE) <= 42452506Simp (tmp->ccr_base - tmp->pf_ccr_offset + 42552506Simp tmp->pf_ccr_realsize))) { 42652506Simp pf->pf_ccrt = tmp->pf_ccrt; 42752506Simp pf->pf_ccrh = tmp->pf_ccrh; 42852506Simp pf->pf_ccr_realsize = tmp->pf_ccr_realsize; 42952506Simp 43052506Simp /* 43152506Simp * pf->pf_ccr_offset = (tmp->pf_ccr_offset - 43252506Simp * tmp->ccr_base) + pf->ccr_base; 43352506Simp */ 43470715Sjon /* pf->pf_ccr_offset = 43552506Simp (tmp->pf_ccr_offset + pf->ccr_base) - 43670715Sjon tmp->ccr_base; */ 43752506Simp pf->pf_ccr_window = tmp->pf_ccr_window; 43852506Simp break; 43952506Simp } 44052506Simp } 44152506Simp if (tmp == NULL) { 44255720Simp pf->ccr_rid = 0; 44355720Simp pf->ccr_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 44470715Sjon &pf->ccr_rid, 0, ~0, 1 << 10, RF_ACTIVE); 44570715Sjon if (!pf->ccr_res) 44652506Simp goto bad; 44770746Simp DEVPRINTF((dev, "ccr_res == %lx-%lx, base=%lx\n", 44870746Simp rman_get_start(pf->ccr_res), rman_get_end(pf->ccr_res), 44970746Simp pf->ccr_base)); 45061788Simp CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY, 45161788Simp pf->ccr_rid, PCCARD_A_MEM_ATTR); 45270715Sjon CARD_SET_MEMORY_OFFSET(device_get_parent(dev), dev, 45370748Simp pf->ccr_rid, pf->ccr_base, &pf->pf_ccr_offset); 45455720Simp pf->pf_ccrt = rman_get_bustag(pf->ccr_res); 45555720Simp pf->pf_ccrh = rman_get_bushandle(pf->ccr_res); 45655720Simp pf->pf_ccr_realsize = 1; 45752506Simp } 45852506Simp 45952506Simp reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX); 46052506Simp reg |= PCCARD_CCR_OPTION_LEVIREQ; 46152506Simp if (pccard_mfc(pf->sc)) { 46252506Simp reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE | 46352506Simp PCCARD_CCR_OPTION_ADDR_DECODE); 46470715Sjon /* 46567167Simp * XXX Need to enable PCCARD_CCR_OPTION_IRQ_ENABLE if 46667167Simp * XXX we have an interrupt handler, but we don't know that 46767167Simp * XXX at this point. 46867167Simp */ 46970715Sjon/* reg |= PCCARD_CCR_OPTION_IREQ_ENABLE;*/ 47052506Simp } 47152506Simp pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg); 47252506Simp 47352506Simp reg = 0; 47452506Simp if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0) 47552506Simp reg |= PCCARD_CCR_STATUS_IOIS8; 47652506Simp if (pf->cfe->flags & PCCARD_CFE_AUDIO) 47752506Simp reg |= PCCARD_CCR_STATUS_AUDIO; 47852506Simp pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg); 47952506Simp 48052506Simp pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0); 48152506Simp 48252506Simp if (pccard_mfc(pf->sc)) { 48352506Simp long tmp, iosize; 48452506Simp 48552506Simp tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase; 48652506Simp /* round up to nearest (2^n)-1 */ 48752506Simp for (iosize = 1; iosize < tmp; iosize <<= 1) 48852506Simp ; 48952506Simp iosize--; 49052506Simp 49152506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE0, 49252506Simp pf->pf_mfc_iobase & 0xff); 49352506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE1, 49452506Simp (pf->pf_mfc_iobase >> 8) & 0xff); 49552506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0); 49652506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0); 49752506Simp 49852506Simp pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize); 49952506Simp } 50052506Simp 50152506Simp#ifdef PCCARDDEBUG 50252506Simp if (pccard_debug) { 50352506Simp STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 50470715Sjon device_printf(tmp->sc->dev, 50555500Simp "function %d CCR at %d offset %x: " 50655500Simp "%x %x %x %x, %x %x %x %x, %x\n", 50770715Sjon tmp->number, tmp->pf_ccr_window, 50855500Simp tmp->pf_ccr_offset, 50955500Simp pccard_ccr_read(tmp, 0x00), 51055500Simp pccard_ccr_read(tmp, 0x02), 51155500Simp pccard_ccr_read(tmp, 0x04), 51255500Simp pccard_ccr_read(tmp, 0x06), 51355500Simp pccard_ccr_read(tmp, 0x0A), 51470715Sjon pccard_ccr_read(tmp, 0x0C), 51555500Simp pccard_ccr_read(tmp, 0x0E), 51655500Simp pccard_ccr_read(tmp, 0x10), 51755500Simp pccard_ccr_read(tmp, 0x12)); 51852506Simp } 51952506Simp } 52052506Simp#endif 52152506Simp pf->pf_flags |= PFF_ENABLED; 52252506Simp return (0); 52352506Simp 52452506Simp bad: 52552506Simp /* 52652506Simp * Decrement the reference count, and power down the socket, if 52752506Simp * necessary. 52852506Simp */ 52952506Simp if (--pf->sc->sc_enabled_count == 0) 53055720Simp POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 53165098Simp DEVPRINTF((dev, "bad --enabled_count = %d\n", pf->sc->sc_enabled_count)); 53252506Simp 53352506Simp return (1); 53452506Simp} 53552506Simp 53652506Simp/* Disable PCCARD function. */ 53752506Simpvoid 53855720Simppccard_function_disable(struct pccard_function *pf) 53952506Simp{ 54052506Simp struct pccard_function *tmp; 54155720Simp device_t dev = pf->sc->dev; 54252506Simp 54352506Simp if (pf->cfe == NULL) 54461788Simp panic("pccard_function_disable: function not initialized"); 54552506Simp 54652506Simp if ((pf->pf_flags & PFF_ENABLED) == 0) { 54752506Simp /* 54852506Simp * Don't do anything if we're already disabled. 54952506Simp */ 55052506Simp return; 55152506Simp } 55252506Simp 55370715Sjon if (pf->intr_handler != NULL) { 55470715Sjon pf->intr_handler = NULL; 55570715Sjon pf->intr_handler_arg = NULL; 55670715Sjon pf->intr_handler_cookie = NULL; 55770715Sjon pccard_ccr_write(pf, PCCARD_CCR_OPTION, 55870715Sjon pccard_ccr_read(pf, PCCARD_CCR_OPTION) & 55970715Sjon ~PCCARD_CCR_OPTION_IREQ_ENABLE); 56070715Sjon 56170715Sjon if (pf->sc->intr_handler_count == 1) { 56270715Sjon struct pccard_ivar *ivar = PCCARD_IVAR(pf->dev); 56370715Sjon struct resource_list_entry *rle = NULL; 56470715Sjon 56570715Sjon pf->sc->intr_handler_count--; 56670762Simp rle = resource_list_find(&ivar->resources, SYS_RES_IRQ, 56770762Simp 0); 56870715Sjon if (rle == NULL) 56970715Sjon panic("No IRQ for pccard?"); 57070715Sjon 57170762Simp bus_teardown_intr(dev, rle->res, 57270762Simp &pf->sc->intr_handler_count); 57370715Sjon } 57470715Sjon } 57570715Sjon 57652506Simp /* 57752506Simp * it's possible for different functions' CCRs to be in the same 57852506Simp * underlying page. Check for that. Note we mark us as disabled 57952506Simp * first to avoid matching ourself. 58052506Simp */ 58152506Simp 58252506Simp pf->pf_flags &= ~PFF_ENABLED; 58352506Simp STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 58452506Simp if ((tmp->pf_flags & PFF_ENABLED) && 58552506Simp (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 58652506Simp ((pf->ccr_base + PCCARD_CCR_SIZE) <= 58752506Simp (tmp->ccr_base - tmp->pf_ccr_offset + tmp->pf_ccr_realsize))) 58852506Simp break; 58952506Simp } 59052506Simp 59152506Simp /* Not used by anyone else; unmap the CCR. */ 59252506Simp if (tmp == NULL) { 59370715Sjon bus_release_resource(dev, SYS_RES_MEMORY, pf->ccr_rid, 59455720Simp pf->ccr_res); 59555720Simp pf->ccr_res = NULL; 59652506Simp } 59752506Simp 59852506Simp /* 59952506Simp * Decrement the reference count, and power down the socket, if 60052506Simp * necessary. 60152506Simp */ 60252506Simp if (--pf->sc->sc_enabled_count == 0) 60355720Simp POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 60455720Simp DEVPRINTF((dev, "--enabled_count = %d\n", pf->sc->sc_enabled_count)); 60552506Simp} 60652506Simp 60755720Simp#if 0 60855720Simp/* XXX These functions are needed, but not like this XXX */ 60952506Simpint 61055720Simppccard_io_map(struct pccard_function *pf, int width, bus_addr_t offset, 61155720Simp bus_size_t size, struct pccard_io_handle *pcihp, int *windowp) 61252506Simp{ 61352506Simp int reg; 61452506Simp 61567167Simp if (pccard_chip_io_map(pf->sc->pct, pf->sc->pch, width, offset, size, 61667167Simp pcihp, windowp)) 61752506Simp return (1); 61852506Simp 61952506Simp /* 62052506Simp * XXX in the multifunction multi-iospace-per-function case, this 62152506Simp * needs to cooperate with io_alloc to make sure that the spaces 62252506Simp * don't overlap, and that the ccr's are set correctly 62352506Simp */ 62452506Simp 62552506Simp if (pccard_mfc(pf->sc)) { 62652506Simp long tmp, iosize; 62752506Simp 62852506Simp if (pf->pf_mfc_iomax == 0) { 62952506Simp pf->pf_mfc_iobase = pcihp->addr + offset; 63052506Simp pf->pf_mfc_iomax = pf->pf_mfc_iobase + size; 63152506Simp } else { 63252506Simp /* this makes the assumption that nothing overlaps */ 63352506Simp if (pf->pf_mfc_iobase > pcihp->addr + offset) 63452506Simp pf->pf_mfc_iobase = pcihp->addr + offset; 63552506Simp if (pf->pf_mfc_iomax < pcihp->addr + offset + size) 63652506Simp pf->pf_mfc_iomax = pcihp->addr + offset + size; 63752506Simp } 63852506Simp 63952506Simp tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase; 64052506Simp /* round up to nearest (2^n)-1 */ 64152506Simp for (iosize = 1; iosize >= tmp; iosize <<= 1) 64252506Simp ; 64352506Simp iosize--; 64452506Simp 64570715Sjon pccard_ccr_write(pf, PCCARD_CCR_IOBASE0, 64655720Simp pf->pf_mfc_iobase & 0xff); 64752506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE1, 64855720Simp (pf->pf_mfc_iobase >> 8) & 0xff); 64952506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0); 65052506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0); 65152506Simp 65252506Simp pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize); 65352506Simp 65452506Simp reg = pccard_ccr_read(pf, PCCARD_CCR_OPTION); 65552506Simp reg |= PCCARD_CCR_OPTION_ADDR_DECODE; 65652506Simp pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg); 65752506Simp } 65852506Simp return (0); 65952506Simp} 66052506Simp 66152506Simpvoid 66255720Simppccard_io_unmap(struct pccard_function *pf, int window) 66352506Simp{ 66452506Simp 66552506Simp pccard_chip_io_unmap(pf->sc->pct, pf->sc->pch, window); 66652506Simp 66752506Simp /* XXX Anything for multi-function cards? */ 66852506Simp} 66952506Simp#endif 67052506Simp 67166058Simp/* 67266058Simp * simulate the old "probe" routine. In the new world order, the driver 67366058Simp * needs to grab devices while in the old they were assigned to the device by 67466058Simp * the pccardd process. These symbols are exported to the upper layers. 67566058Simp */ 67674636Simpstatic int 67774636Simppccard_compat_do_probe(device_t bus, device_t dev) 67866058Simp{ 67966058Simp return (CARD_COMPAT_MATCH(dev)); 68066058Simp} 68166058Simp 68274636Simpstatic int 68374636Simppccard_compat_do_attach(device_t bus, device_t dev) 68466058Simp{ 68566058Simp int err; 68666058Simp 68766058Simp err = CARD_COMPAT_PROBE(dev); 68866058Simp if (err == 0) 68966058Simp err = CARD_COMPAT_ATTACH(dev); 69066058Simp return (err); 69166058Simp} 69266058Simp 69353873Simp#define PCCARD_NPORT 2 69453873Simp#define PCCARD_NMEM 5 69553873Simp#define PCCARD_NIRQ 1 69653873Simp#define PCCARD_NDRQ 0 69753873Simp 69852506Simpstatic int 69952506Simppccard_add_children(device_t dev, int busno) 70052506Simp{ 70159193Simp /* Call parent to scan for any current children */ 70274632Simp return (0); 70352506Simp} 70452506Simp 70552506Simpstatic int 70652506Simppccard_probe(device_t dev) 70752506Simp{ 70867333Simp device_set_desc(dev, "16-bit PCCard bus"); 70974632Simp return (pccard_add_children(dev, device_get_unit(dev))); 71052506Simp} 71152506Simp 71259193Simpstatic int 71359193Simppccard_attach(device_t dev) 71459193Simp{ 71564850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 71661788Simp 71759193Simp sc->dev = dev; 71861788Simp sc->sc_enabled_count = 0; 71974632Simp return (bus_generic_attach(dev)); 72059193Simp} 72159193Simp 72253873Simpstatic void 72353873Simppccard_print_resources(struct resource_list *rl, const char *name, int type, 72453873Simp int count, const char *format) 72553873Simp{ 72653873Simp struct resource_list_entry *rle; 72753873Simp int printed; 72853873Simp int i; 72953873Simp 73053873Simp printed = 0; 73153873Simp for (i = 0; i < count; i++) { 73253873Simp rle = resource_list_find(rl, type, i); 73353873Simp if (rle) { 73453873Simp if (printed == 0) 73553873Simp printf(" %s ", name); 73653873Simp else if (printed > 0) 73753873Simp printf(","); 73853873Simp printed++; 73953873Simp printf(format, rle->start); 74053873Simp if (rle->count > 1) { 74153873Simp printf("-"); 74253873Simp printf(format, rle->start + rle->count - 1); 74353873Simp } 74453873Simp } else if (i > 3) { 74553873Simp /* check the first few regardless */ 74653873Simp break; 74753873Simp } 74853873Simp } 74953873Simp} 75053873Simp 75153873Simpstatic int 75253873Simppccard_print_child(device_t dev, device_t child) 75353873Simp{ 75466847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 75553873Simp struct resource_list *rl = &devi->resources; 75653873Simp int retval = 0; 75753873Simp 75853873Simp retval += bus_print_child_header(dev, child); 75953873Simp retval += printf(" at"); 76053873Simp 76153873Simp if (devi) { 76253873Simp pccard_print_resources(rl, "port", SYS_RES_IOPORT, 76353873Simp PCCARD_NPORT, "%#lx"); 76453873Simp pccard_print_resources(rl, "iomem", SYS_RES_MEMORY, 76553873Simp PCCARD_NMEM, "%#lx"); 76653873Simp pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ, 76753873Simp "%ld"); 76870715Sjon pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ, 76953873Simp "%ld"); 77067269Simp retval += printf(" function %d config %d", devi->fcn->number, 77167269Simp devi->fcn->cfe->number); 77253873Simp } 77353873Simp 77453873Simp retval += bus_print_child_footer(dev, child); 77553873Simp 77653873Simp return (retval); 77753873Simp} 77853873Simp 77953873Simpstatic int 78053873Simppccard_set_resource(device_t dev, device_t child, int type, int rid, 78153873Simp u_long start, u_long count) 78253873Simp{ 78366847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 78453873Simp struct resource_list *rl = &devi->resources; 78553873Simp 78653873Simp if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY 78753873Simp && type != SYS_RES_IRQ && type != SYS_RES_DRQ) 78874632Simp return (EINVAL); 78953873Simp if (rid < 0) 79074632Simp return (EINVAL); 79153873Simp if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT) 79274632Simp return (EINVAL); 79353873Simp if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM) 79474632Simp return (EINVAL); 79553873Simp if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ) 79674632Simp return (EINVAL); 79753873Simp if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ) 79874632Simp return (EINVAL); 79953873Simp 80053873Simp resource_list_add(rl, type, rid, start, start + count - 1, count); 80153873Simp 80274632Simp return (0); 80353873Simp} 80453873Simp 80553873Simpstatic int 80653873Simppccard_get_resource(device_t dev, device_t child, int type, int rid, 80753873Simp u_long *startp, u_long *countp) 80853873Simp{ 80966847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 81053873Simp struct resource_list *rl = &devi->resources; 81153873Simp struct resource_list_entry *rle; 81253873Simp 81353873Simp rle = resource_list_find(rl, type, rid); 81453873Simp if (!rle) 81574632Simp return (ENOENT); 81670715Sjon 81753873Simp if (startp) 81853873Simp *startp = rle->start; 81953873Simp if (countp) 82053873Simp *countp = rle->count; 82153873Simp 82274632Simp return (0); 82353873Simp} 82453873Simp 82553873Simpstatic void 82653873Simppccard_delete_resource(device_t dev, device_t child, int type, int rid) 82753873Simp{ 82866847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 82953873Simp struct resource_list *rl = &devi->resources; 83053873Simp resource_list_delete(rl, type, rid); 83153873Simp} 83253873Simp 83359193Simpstatic int 83459193Simppccard_set_res_flags(device_t dev, device_t child, int type, int rid, 83559193Simp u_int32_t flags) 83659193Simp{ 83774632Simp return (CARD_SET_RES_FLAGS(device_get_parent(dev), child, type, 83874632Simp rid, flags)); 83959193Simp} 84059193Simp 84159193Simpstatic int 84259193Simppccard_set_memory_offset(device_t dev, device_t child, int rid, 84370748Simp u_int32_t offset, u_int32_t *deltap) 84470715Sjon 84559193Simp{ 84674632Simp return (CARD_SET_MEMORY_OFFSET(device_get_parent(dev), child, rid, 84774632Simp offset, deltap)); 84859193Simp} 84959193Simp 85066058Simpstatic int 85166058Simppccard_read_ivar(device_t bus, device_t child, int which, u_char *result) 85266058Simp{ 85366847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 85466779Simp struct pccard_function *func = devi->fcn; 85566779Simp struct pccard_softc *sc = PCCARD_SOFTC(bus); 85666779Simp 85766058Simp /* PCCARD_IVAR_ETHADDR unhandled from oldcard */ 85866779Simp switch (which) { 85966779Simp default: 86066779Simp case PCCARD_IVAR_ETHADDR: 86166779Simp return (ENOENT); 86266779Simp break; 86366779Simp case PCCARD_IVAR_VENDOR: 86466779Simp *(u_int32_t *) result = sc->card.manufacturer; 86566779Simp break; 86666779Simp case PCCARD_IVAR_PRODUCT: 86766779Simp *(u_int32_t *) result = sc->card.product; 86866779Simp break; 86966779Simp case PCCARD_IVAR_FUNCTION_NUMBER: 87066847Simp if (!func) { 87166847Simp device_printf(bus, "No function number, bug!\n"); 87266847Simp return (ENOENT); 87366847Simp } 87466847Simp *(u_int32_t *) result = func->number; 87566779Simp break; 87666779Simp case PCCARD_IVAR_VENDOR_STR: 87766779Simp *(char **) result = sc->card.cis1_info[0]; 87866779Simp break; 87966779Simp case PCCARD_IVAR_PRODUCT_STR: 88066779Simp *(char **) result = sc->card.cis1_info[1]; 88166779Simp break; 88266779Simp case PCCARD_IVAR_CIS3_STR: 88366779Simp *(char **) result = sc->card.cis1_info[2]; 88466779Simp break; 88567167Simp case PCCARD_IVAR_CIS4_STR: 88667167Simp *(char **) result = sc->card.cis1_info[2]; 88767167Simp break; 88866779Simp } 88966779Simp return (0); 89066058Simp} 89166058Simp 89266779Simpstatic void 89366779Simppccard_driver_added(device_t dev, driver_t *driver) 89466779Simp{ 89567167Simp /* 89667167Simp * XXX eventually we need to attach stuff when we know we 89767167Simp * XXX have kids. For now we do nothing because we normally 89867167Simp * XXX add children ourselves. We don't want to necessarily 89967167Simp * XXX force a reprobe. 90067167Simp */ 90166779Simp} 90266058Simp 90367242Simpstatic struct resource * 90467242Simppccard_alloc_resource(device_t dev, device_t child, int type, int *rid, 90567242Simp u_long start, u_long end, u_long count, u_int flags) 90667242Simp{ 90770715Sjon struct resource_list_entry *rle = NULL; 90867242Simp 90970715Sjon /* XXX: This is an ugly way to fudge the resources. */ 91070715Sjon 91167242Simp if (device_get_parent(child) == dev) { 91270715Sjon struct pccard_ivar *devi = PCCARD_IVAR(child); 91370715Sjon struct resource_list *rl = &devi->resources; 91470715Sjon 91570715Sjon rle = resource_list_find(rl, type, *rid); 91667242Simp } 91770715Sjon 91870715Sjon if (rle != NULL) { 91970715Sjon if (flags & RF_ACTIVE) 92070715Sjon bus_activate_resource(dev, type, rle->rid, rle->res); 92170715Sjon return (rle->res); 92267269Simp } 92367242Simp return (bus_generic_alloc_resource(dev, child, type, rid, start, 92467242Simp end, count, flags)); 92567242Simp} 92667242Simp 92767242Simpstatic int 92867242Simppccard_release_resource(device_t dev, device_t child, int type, int rid, 92967242Simp struct resource *r) 93067242Simp{ 93170715Sjon struct resource_list_entry *rle = NULL; 93270715Sjon 93370715Sjon if (device_get_parent(child) == dev) { 93470715Sjon struct pccard_ivar *devi = PCCARD_IVAR(child); 93570715Sjon struct resource_list *rl = &devi->resources; 93670715Sjon 93770715Sjon rle = resource_list_find(rl, type, rid); 93870715Sjon } 93970715Sjon 94070715Sjon if (rle != NULL) { 94174632Simp return (bus_deactivate_resource(dev, type, rle->rid, rle->res)); 94270715Sjon } 94370715Sjon 94474632Simp return (bus_generic_release_resource(dev, child, type, rid, r)); 94567242Simp} 94667242Simp 94767242Simpstatic int 94867242Simppccard_activate_resource(device_t dev, device_t child, int type, int rid, 94967242Simp struct resource *r) 95067242Simp{ 95167269Simp /* XXX need to write to the COR to activate this for mf cards */ 95270715Sjon struct resource_list_entry *rle = NULL; 95370715Sjon 95470715Sjon if (device_get_parent(child) == dev) { 95570715Sjon struct pccard_ivar *devi = PCCARD_IVAR(child); 95670715Sjon struct resource_list *rl = &devi->resources; 95770715Sjon 95870715Sjon rle = resource_list_find(rl, type, rid); 95970715Sjon } 96070715Sjon 96170715Sjon if (rle != NULL) { 96270715Sjon return (bus_activate_resource(dev, type, rle->rid, rle->res)); 96370715Sjon } 96470715Sjon 96567242Simp return (bus_generic_activate_resource(dev, child, type, rid, r)); 96667242Simp} 96767242Simp 96867242Simpstatic int 96967242Simppccard_deactivate_resource(device_t dev, device_t child, int type, int rid, 97067242Simp struct resource *r) 97167242Simp{ 97267269Simp /* XXX need to write to the COR to deactivate this for mf cards */ 97370715Sjon struct resource_list_entry *rle = NULL; 97470715Sjon 97570715Sjon if (device_get_parent(child) == dev) { 97670715Sjon struct pccard_ivar *devi = PCCARD_IVAR(child); 97770715Sjon struct resource_list *rl = &devi->resources; 97870715Sjon 97970715Sjon rle = resource_list_find(rl, type, rid); 98070715Sjon } 98170715Sjon 98270715Sjon if (rle != NULL) { 98370715Sjon return (bus_deactivate_resource(dev, type, rle->rid, rle->res)); 98470715Sjon } 98570715Sjon 98667242Simp return (bus_generic_deactivate_resource(dev, child, type, rid, r)); 98767242Simp} 98867242Simp 98967333Simpstatic void 99067333Simppccard_child_detached(device_t parent, device_t dev) 99167333Simp{ 99267333Simp struct pccard_ivar *ivar = PCCARD_IVAR(dev); 99367333Simp 99467333Simp if (parent == device_get_parent(dev)) 99567333Simp free(ivar, M_DEVBUF); 99667333Simp} 99767333Simp 99870715Sjonstatic void 99970762Simppccard_intr(void *arg) 100070762Simp{ 100170762Simp struct pccard_softc *sc = (struct pccard_softc *) arg; 100270715Sjon struct pccard_function *pf; 100370762Simp STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 100470715Sjon if (pf->intr_handler != NULL) { 100570715Sjon int reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS); 100670715Sjon if (reg & PCCARD_CCR_STATUS_INTR) { 100770715Sjon pccard_ccr_write(pf, PCCARD_CCR_STATUS, 100870762Simp reg & ~PCCARD_CCR_STATUS_INTR); 100970715Sjon pf->intr_handler(pf->intr_handler_arg); 101070715Sjon } 101170715Sjon } 101270715Sjon } 101370715Sjon} 101470715Sjon 101570715Sjonstatic int 101670762Simppccard_setup_intr(device_t dev, device_t child, struct resource *irq, 101770762Simp int flags, driver_intr_t *intr, void *arg, void **cookiep) 101870715Sjon{ 101970715Sjon struct pccard_ivar *ivar = PCCARD_IVAR(child); 102070715Sjon struct pccard_function *func = ivar->fcn; 102170715Sjon struct resource_list_entry *rle = NULL; 102270715Sjon struct pccard_softc *sc = device_get_softc(dev); 102370715Sjon 102470715Sjon if (func->intr_handler != NULL) 102570762Simp panic("Only one interrupt handler per function allowed\n"); 102670715Sjon 102770715Sjon rle = resource_list_find(&ivar->resources, SYS_RES_IRQ, 0); 102870715Sjon if (rle == NULL || rle->res != irq) 102970715Sjon panic("irq in setup_intr does not match allocated irq\n"); 103070715Sjon 103170715Sjon func->intr_handler = intr; 103270715Sjon func->intr_handler_arg = arg; 103370761Simp func->intr_handler_cookie = *cookiep = func; 103470715Sjon pccard_ccr_write(func, PCCARD_CCR_OPTION, 103570762Simp pccard_ccr_read(func, PCCARD_CCR_OPTION) | 103670762Simp PCCARD_CCR_OPTION_IREQ_ENABLE); 103770715Sjon 103870715Sjon if (sc->intr_handler_count++ == 0) { 103970715Sjon rle = resource_list_find(&ivar->resources, SYS_RES_IRQ, 0); 104070715Sjon if (rle == NULL) 104170715Sjon panic("No IRQ for pccard?"); 104270715Sjon 104370715Sjon bus_setup_intr(dev, rle->res, INTR_TYPE_TTY/* | INTR_FAST*/, 104470762Simp pccard_intr, sc, (void*)&sc->intr_handler_count); 104570715Sjon } 104674632Simp return (0); 104770715Sjon} 104870715Sjon 104970715Sjonstatic int 105070762Simppccard_teardown_intr(device_t dev, device_t child, struct resource *r, 105170762Simp void *cookie) 105270715Sjon{ 105370715Sjon struct pccard_ivar *ivar = PCCARD_IVAR(child); 105470715Sjon struct pccard_function *func = ivar->fcn; 105570715Sjon struct pccard_softc *sc = device_get_softc(dev); 105670715Sjon 105770715Sjon if (func->intr_handler_cookie != cookie) 105870715Sjon panic("pccard teardown of unknown interrupt handler\n"); 105970715Sjon 106070715Sjon func->intr_handler = NULL; 106170715Sjon func->intr_handler_arg = NULL; 106270715Sjon func->intr_handler_cookie = NULL; 106370715Sjon pccard_ccr_write(func, PCCARD_CCR_OPTION, 106470762Simp pccard_ccr_read(func, PCCARD_CCR_OPTION) & 106570762Simp ~PCCARD_CCR_OPTION_IREQ_ENABLE); 106670715Sjon 106770715Sjon if (--sc->intr_handler_count == 0) { 106870715Sjon struct resource_list_entry *rle = NULL; 106970715Sjon 107070715Sjon rle = resource_list_find(&ivar->resources, SYS_RES_IRQ, 0); 107170715Sjon if (rle == NULL) 107270715Sjon panic("No IRQ for pccard?"); 107370715Sjon 107470715Sjon bus_teardown_intr(dev, rle->res, &sc->intr_handler_count); 107570715Sjon } 107674632Simp return (0); 107770715Sjon} 107870715Sjon 107952506Simpstatic device_method_t pccard_methods[] = { 108052506Simp /* Device interface */ 108152506Simp DEVMETHOD(device_probe, pccard_probe), 108259193Simp DEVMETHOD(device_attach, pccard_attach), 108361788Simp DEVMETHOD(device_detach, bus_generic_detach), 108452506Simp DEVMETHOD(device_shutdown, bus_generic_shutdown), 108552506Simp DEVMETHOD(device_suspend, bus_generic_suspend), 108652506Simp DEVMETHOD(device_resume, bus_generic_resume), 108752506Simp 108852506Simp /* Bus interface */ 108952506Simp DEVMETHOD(bus_print_child, pccard_print_child), 109066779Simp DEVMETHOD(bus_driver_added, pccard_driver_added), 109167333Simp DEVMETHOD(bus_child_detached, pccard_child_detached), 109267242Simp DEVMETHOD(bus_alloc_resource, pccard_alloc_resource), 109367242Simp DEVMETHOD(bus_release_resource, pccard_release_resource), 109467242Simp DEVMETHOD(bus_activate_resource, pccard_activate_resource), 109567242Simp DEVMETHOD(bus_deactivate_resource, pccard_deactivate_resource), 109670715Sjon DEVMETHOD(bus_setup_intr, pccard_setup_intr), 109770715Sjon DEVMETHOD(bus_teardown_intr, pccard_teardown_intr), 109852506Simp DEVMETHOD(bus_set_resource, pccard_set_resource), 109952506Simp DEVMETHOD(bus_get_resource, pccard_get_resource), 110052506Simp DEVMETHOD(bus_delete_resource, pccard_delete_resource), 110166058Simp DEVMETHOD(bus_read_ivar, pccard_read_ivar), 110252506Simp 110359193Simp /* Card Interface */ 110459193Simp DEVMETHOD(card_set_res_flags, pccard_set_res_flags), 110559193Simp DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset), 110659193Simp DEVMETHOD(card_get_type, pccard_card_gettype), 110759193Simp DEVMETHOD(card_attach_card, pccard_attach_card), 110859193Simp DEVMETHOD(card_detach_card, pccard_detach_card), 110974636Simp DEVMETHOD(card_compat_do_probe, pccard_compat_do_probe), 111074636Simp DEVMETHOD(card_compat_do_attach, pccard_compat_do_attach), 111159193Simp 111252506Simp { 0, 0 } 111352506Simp}; 111452506Simp 111552506Simpstatic driver_t pccard_driver = { 111652506Simp "pccard", 111752506Simp pccard_methods, 111864850Simp sizeof(struct pccard_softc) 111952506Simp}; 112052506Simp 112152506Simpdevclass_t pccard_devclass; 112252506Simp 112353873SimpDRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0); 112452506SimpDRIVER_MODULE(pccard, pc98pcic, pccard_driver, pccard_devclass, 0, 0); 112552506SimpDRIVER_MODULE(pccard, pccbb, pccard_driver, pccard_devclass, 0, 0); 112653873SimpDRIVER_MODULE(pccard, tcic, pccard_driver, pccard_devclass, 0, 0); 112764927SimpMODULE_VERSION(pccard, 1); 112870715Sjon/*MODULE_DEPEND(pccard, pcic, 1, 1, 1);*/ 1129