pccard.c revision 75756
166200Simp/* $NetBSD: pcmcia.c,v 1.23 2000/07/28 19:17:02 drochner Exp $ */ 252506Simp/* $FreeBSD: head/sys/dev/pccard/pccard.c 75756 2001-04-21 02:29:09Z 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++) { 37375756Simp if (cfe->iores[i]) { 37475756Simp resource_list_delete(rl, SYS_RES_IOPORT, i); 37570715Sjon bus_release_resource(bus, SYS_RES_IOPORT, 37667187Simp cfe->iorid[i], cfe->iores[i]); 37775756Simp } 37867187Simp cfe->iores[i] = NULL; 37967187Simp } 38067187Simp if (cfe->irqmask && cfe->irqres) { 38167242Simp resource_list_delete(rl, SYS_RES_IRQ, cfe->irqrid); 38267242Simp bus_release_resource(bus, SYS_RES_IRQ, 38367187Simp cfe->irqrid, cfe->irqres); 38467187Simp cfe->irqres = NULL; 38567187Simp } 38667167Simp } 38752506Simp} 38852506Simp 38952506Simp/* Enable a PCCARD function */ 39052506Simpint 39155720Simppccard_function_enable(struct pccard_function *pf) 39252506Simp{ 39352506Simp struct pccard_function *tmp; 39452506Simp int reg; 39555720Simp device_t dev = pf->sc->dev; 39670746Simp 39767333Simp if (pf->cfe == NULL) { 39867333Simp DEVPRVERBOSE((dev, "No config entry could be allocated.\n")); 39974632Simp return (ENOMEM); 40067333Simp } 40152506Simp 40252506Simp /* 40352506Simp * Increase the reference count on the socket, enabling power, if 40452506Simp * necessary. 40552506Simp */ 40652506Simp if (pf->sc->sc_enabled_count++ == 0) 40755720Simp POWER_ENABLE_SOCKET(device_get_parent(dev), dev); 40855720Simp DEVPRINTF((dev, "++enabled_count = %d\n", pf->sc->sc_enabled_count)); 40952506Simp 41052506Simp if (pf->pf_flags & PFF_ENABLED) { 41152506Simp /* 41252506Simp * Don't do anything if we're already enabled. 41352506Simp */ 41452506Simp return (0); 41552506Simp } 41652506Simp 41752506Simp /* 41852506Simp * it's possible for different functions' CCRs to be in the same 41952506Simp * underlying page. Check for that. 42052506Simp */ 42152506Simp STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 42252506Simp if ((tmp->pf_flags & PFF_ENABLED) && 42352506Simp (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 42452506Simp ((pf->ccr_base + PCCARD_CCR_SIZE) <= 42552506Simp (tmp->ccr_base - tmp->pf_ccr_offset + 42652506Simp tmp->pf_ccr_realsize))) { 42752506Simp pf->pf_ccrt = tmp->pf_ccrt; 42852506Simp pf->pf_ccrh = tmp->pf_ccrh; 42952506Simp pf->pf_ccr_realsize = tmp->pf_ccr_realsize; 43052506Simp 43152506Simp /* 43252506Simp * pf->pf_ccr_offset = (tmp->pf_ccr_offset - 43352506Simp * tmp->ccr_base) + pf->ccr_base; 43452506Simp */ 43570715Sjon /* pf->pf_ccr_offset = 43652506Simp (tmp->pf_ccr_offset + pf->ccr_base) - 43770715Sjon tmp->ccr_base; */ 43852506Simp pf->pf_ccr_window = tmp->pf_ccr_window; 43952506Simp break; 44052506Simp } 44152506Simp } 44252506Simp if (tmp == NULL) { 44355720Simp pf->ccr_rid = 0; 44455720Simp pf->ccr_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 44570715Sjon &pf->ccr_rid, 0, ~0, 1 << 10, RF_ACTIVE); 44670715Sjon if (!pf->ccr_res) 44752506Simp goto bad; 44870746Simp DEVPRINTF((dev, "ccr_res == %lx-%lx, base=%lx\n", 44970746Simp rman_get_start(pf->ccr_res), rman_get_end(pf->ccr_res), 45070746Simp pf->ccr_base)); 45161788Simp CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY, 45261788Simp pf->ccr_rid, PCCARD_A_MEM_ATTR); 45370715Sjon CARD_SET_MEMORY_OFFSET(device_get_parent(dev), dev, 45470748Simp pf->ccr_rid, pf->ccr_base, &pf->pf_ccr_offset); 45555720Simp pf->pf_ccrt = rman_get_bustag(pf->ccr_res); 45655720Simp pf->pf_ccrh = rman_get_bushandle(pf->ccr_res); 45755720Simp pf->pf_ccr_realsize = 1; 45852506Simp } 45952506Simp 46052506Simp reg = (pf->cfe->number & PCCARD_CCR_OPTION_CFINDEX); 46152506Simp reg |= PCCARD_CCR_OPTION_LEVIREQ; 46252506Simp if (pccard_mfc(pf->sc)) { 46352506Simp reg |= (PCCARD_CCR_OPTION_FUNC_ENABLE | 46452506Simp PCCARD_CCR_OPTION_ADDR_DECODE); 46570715Sjon /* 46667167Simp * XXX Need to enable PCCARD_CCR_OPTION_IRQ_ENABLE if 46767167Simp * XXX we have an interrupt handler, but we don't know that 46867167Simp * XXX at this point. 46967167Simp */ 47070715Sjon/* reg |= PCCARD_CCR_OPTION_IREQ_ENABLE;*/ 47152506Simp } 47252506Simp pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg); 47352506Simp 47452506Simp reg = 0; 47552506Simp if ((pf->cfe->flags & PCCARD_CFE_IO16) == 0) 47652506Simp reg |= PCCARD_CCR_STATUS_IOIS8; 47752506Simp if (pf->cfe->flags & PCCARD_CFE_AUDIO) 47852506Simp reg |= PCCARD_CCR_STATUS_AUDIO; 47952506Simp pccard_ccr_write(pf, PCCARD_CCR_STATUS, reg); 48052506Simp 48152506Simp pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0); 48252506Simp 48352506Simp if (pccard_mfc(pf->sc)) { 48452506Simp long tmp, iosize; 48552506Simp 48652506Simp tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase; 48752506Simp /* round up to nearest (2^n)-1 */ 48852506Simp for (iosize = 1; iosize < tmp; iosize <<= 1) 48952506Simp ; 49052506Simp iosize--; 49152506Simp 49252506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE0, 49352506Simp pf->pf_mfc_iobase & 0xff); 49452506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE1, 49552506Simp (pf->pf_mfc_iobase >> 8) & 0xff); 49652506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0); 49752506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0); 49852506Simp 49952506Simp pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize); 50052506Simp } 50152506Simp 50252506Simp#ifdef PCCARDDEBUG 50352506Simp if (pccard_debug) { 50452506Simp STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 50570715Sjon device_printf(tmp->sc->dev, 50655500Simp "function %d CCR at %d offset %x: " 50755500Simp "%x %x %x %x, %x %x %x %x, %x\n", 50870715Sjon tmp->number, tmp->pf_ccr_window, 50955500Simp tmp->pf_ccr_offset, 51055500Simp pccard_ccr_read(tmp, 0x00), 51155500Simp pccard_ccr_read(tmp, 0x02), 51255500Simp pccard_ccr_read(tmp, 0x04), 51355500Simp pccard_ccr_read(tmp, 0x06), 51455500Simp pccard_ccr_read(tmp, 0x0A), 51570715Sjon pccard_ccr_read(tmp, 0x0C), 51655500Simp pccard_ccr_read(tmp, 0x0E), 51755500Simp pccard_ccr_read(tmp, 0x10), 51855500Simp pccard_ccr_read(tmp, 0x12)); 51952506Simp } 52052506Simp } 52152506Simp#endif 52252506Simp pf->pf_flags |= PFF_ENABLED; 52352506Simp return (0); 52452506Simp 52552506Simp bad: 52652506Simp /* 52752506Simp * Decrement the reference count, and power down the socket, if 52852506Simp * necessary. 52952506Simp */ 53052506Simp if (--pf->sc->sc_enabled_count == 0) 53155720Simp POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 53265098Simp DEVPRINTF((dev, "bad --enabled_count = %d\n", pf->sc->sc_enabled_count)); 53352506Simp 53452506Simp return (1); 53552506Simp} 53652506Simp 53752506Simp/* Disable PCCARD function. */ 53852506Simpvoid 53955720Simppccard_function_disable(struct pccard_function *pf) 54052506Simp{ 54152506Simp struct pccard_function *tmp; 54255720Simp device_t dev = pf->sc->dev; 54352506Simp 54452506Simp if (pf->cfe == NULL) 54561788Simp panic("pccard_function_disable: function not initialized"); 54652506Simp 54752506Simp if ((pf->pf_flags & PFF_ENABLED) == 0) { 54852506Simp /* 54952506Simp * Don't do anything if we're already disabled. 55052506Simp */ 55152506Simp return; 55252506Simp } 55352506Simp 55470715Sjon if (pf->intr_handler != NULL) { 55570715Sjon pf->intr_handler = NULL; 55670715Sjon pf->intr_handler_arg = NULL; 55770715Sjon pf->intr_handler_cookie = NULL; 55870715Sjon pccard_ccr_write(pf, PCCARD_CCR_OPTION, 55970715Sjon pccard_ccr_read(pf, PCCARD_CCR_OPTION) & 56070715Sjon ~PCCARD_CCR_OPTION_IREQ_ENABLE); 56170715Sjon 56270715Sjon if (pf->sc->intr_handler_count == 1) { 56370715Sjon struct pccard_ivar *ivar = PCCARD_IVAR(pf->dev); 56470715Sjon struct resource_list_entry *rle = NULL; 56570715Sjon 56670715Sjon pf->sc->intr_handler_count--; 56770762Simp rle = resource_list_find(&ivar->resources, SYS_RES_IRQ, 56870762Simp 0); 56970715Sjon if (rle == NULL) 57070715Sjon panic("No IRQ for pccard?"); 57170715Sjon 57270762Simp bus_teardown_intr(dev, rle->res, 57370762Simp &pf->sc->intr_handler_count); 57470715Sjon } 57570715Sjon } 57670715Sjon 57752506Simp /* 57852506Simp * it's possible for different functions' CCRs to be in the same 57952506Simp * underlying page. Check for that. Note we mark us as disabled 58052506Simp * first to avoid matching ourself. 58152506Simp */ 58252506Simp 58352506Simp pf->pf_flags &= ~PFF_ENABLED; 58452506Simp STAILQ_FOREACH(tmp, &pf->sc->card.pf_head, pf_list) { 58552506Simp if ((tmp->pf_flags & PFF_ENABLED) && 58652506Simp (pf->ccr_base >= (tmp->ccr_base - tmp->pf_ccr_offset)) && 58752506Simp ((pf->ccr_base + PCCARD_CCR_SIZE) <= 58852506Simp (tmp->ccr_base - tmp->pf_ccr_offset + tmp->pf_ccr_realsize))) 58952506Simp break; 59052506Simp } 59152506Simp 59252506Simp /* Not used by anyone else; unmap the CCR. */ 59352506Simp if (tmp == NULL) { 59470715Sjon bus_release_resource(dev, SYS_RES_MEMORY, pf->ccr_rid, 59555720Simp pf->ccr_res); 59655720Simp pf->ccr_res = NULL; 59752506Simp } 59852506Simp 59952506Simp /* 60052506Simp * Decrement the reference count, and power down the socket, if 60152506Simp * necessary. 60252506Simp */ 60352506Simp if (--pf->sc->sc_enabled_count == 0) 60455720Simp POWER_DISABLE_SOCKET(device_get_parent(dev), dev); 60555720Simp DEVPRINTF((dev, "--enabled_count = %d\n", pf->sc->sc_enabled_count)); 60652506Simp} 60752506Simp 60855720Simp#if 0 60955720Simp/* XXX These functions are needed, but not like this XXX */ 61052506Simpint 61155720Simppccard_io_map(struct pccard_function *pf, int width, bus_addr_t offset, 61255720Simp bus_size_t size, struct pccard_io_handle *pcihp, int *windowp) 61352506Simp{ 61452506Simp int reg; 61552506Simp 61667167Simp if (pccard_chip_io_map(pf->sc->pct, pf->sc->pch, width, offset, size, 61767167Simp pcihp, windowp)) 61852506Simp return (1); 61952506Simp 62052506Simp /* 62152506Simp * XXX in the multifunction multi-iospace-per-function case, this 62252506Simp * needs to cooperate with io_alloc to make sure that the spaces 62352506Simp * don't overlap, and that the ccr's are set correctly 62452506Simp */ 62552506Simp 62652506Simp if (pccard_mfc(pf->sc)) { 62752506Simp long tmp, iosize; 62852506Simp 62952506Simp if (pf->pf_mfc_iomax == 0) { 63052506Simp pf->pf_mfc_iobase = pcihp->addr + offset; 63152506Simp pf->pf_mfc_iomax = pf->pf_mfc_iobase + size; 63252506Simp } else { 63352506Simp /* this makes the assumption that nothing overlaps */ 63452506Simp if (pf->pf_mfc_iobase > pcihp->addr + offset) 63552506Simp pf->pf_mfc_iobase = pcihp->addr + offset; 63652506Simp if (pf->pf_mfc_iomax < pcihp->addr + offset + size) 63752506Simp pf->pf_mfc_iomax = pcihp->addr + offset + size; 63852506Simp } 63952506Simp 64052506Simp tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase; 64152506Simp /* round up to nearest (2^n)-1 */ 64252506Simp for (iosize = 1; iosize >= tmp; iosize <<= 1) 64352506Simp ; 64452506Simp iosize--; 64552506Simp 64670715Sjon pccard_ccr_write(pf, PCCARD_CCR_IOBASE0, 64755720Simp pf->pf_mfc_iobase & 0xff); 64852506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE1, 64955720Simp (pf->pf_mfc_iobase >> 8) & 0xff); 65052506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0); 65152506Simp pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0); 65252506Simp 65352506Simp pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize); 65452506Simp 65552506Simp reg = pccard_ccr_read(pf, PCCARD_CCR_OPTION); 65652506Simp reg |= PCCARD_CCR_OPTION_ADDR_DECODE; 65752506Simp pccard_ccr_write(pf, PCCARD_CCR_OPTION, reg); 65852506Simp } 65952506Simp return (0); 66052506Simp} 66152506Simp 66252506Simpvoid 66355720Simppccard_io_unmap(struct pccard_function *pf, int window) 66452506Simp{ 66552506Simp 66652506Simp pccard_chip_io_unmap(pf->sc->pct, pf->sc->pch, window); 66752506Simp 66852506Simp /* XXX Anything for multi-function cards? */ 66952506Simp} 67052506Simp#endif 67152506Simp 67266058Simp/* 67366058Simp * simulate the old "probe" routine. In the new world order, the driver 67466058Simp * needs to grab devices while in the old they were assigned to the device by 67566058Simp * the pccardd process. These symbols are exported to the upper layers. 67666058Simp */ 67774636Simpstatic int 67874636Simppccard_compat_do_probe(device_t bus, device_t dev) 67966058Simp{ 68066058Simp return (CARD_COMPAT_MATCH(dev)); 68166058Simp} 68266058Simp 68374636Simpstatic int 68474636Simppccard_compat_do_attach(device_t bus, device_t dev) 68566058Simp{ 68666058Simp int err; 68766058Simp 68866058Simp err = CARD_COMPAT_PROBE(dev); 68966058Simp if (err == 0) 69066058Simp err = CARD_COMPAT_ATTACH(dev); 69166058Simp return (err); 69266058Simp} 69366058Simp 69453873Simp#define PCCARD_NPORT 2 69553873Simp#define PCCARD_NMEM 5 69653873Simp#define PCCARD_NIRQ 1 69753873Simp#define PCCARD_NDRQ 0 69853873Simp 69952506Simpstatic int 70052506Simppccard_add_children(device_t dev, int busno) 70152506Simp{ 70259193Simp /* Call parent to scan for any current children */ 70374632Simp return (0); 70452506Simp} 70552506Simp 70652506Simpstatic int 70752506Simppccard_probe(device_t dev) 70852506Simp{ 70967333Simp device_set_desc(dev, "16-bit PCCard bus"); 71074632Simp return (pccard_add_children(dev, device_get_unit(dev))); 71152506Simp} 71252506Simp 71359193Simpstatic int 71459193Simppccard_attach(device_t dev) 71559193Simp{ 71664850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 71761788Simp 71859193Simp sc->dev = dev; 71961788Simp sc->sc_enabled_count = 0; 72074632Simp return (bus_generic_attach(dev)); 72159193Simp} 72259193Simp 72353873Simpstatic void 72453873Simppccard_print_resources(struct resource_list *rl, const char *name, int type, 72553873Simp int count, const char *format) 72653873Simp{ 72753873Simp struct resource_list_entry *rle; 72853873Simp int printed; 72953873Simp int i; 73053873Simp 73153873Simp printed = 0; 73253873Simp for (i = 0; i < count; i++) { 73353873Simp rle = resource_list_find(rl, type, i); 73453873Simp if (rle) { 73553873Simp if (printed == 0) 73653873Simp printf(" %s ", name); 73753873Simp else if (printed > 0) 73853873Simp printf(","); 73953873Simp printed++; 74053873Simp printf(format, rle->start); 74153873Simp if (rle->count > 1) { 74253873Simp printf("-"); 74353873Simp printf(format, rle->start + rle->count - 1); 74453873Simp } 74553873Simp } else if (i > 3) { 74653873Simp /* check the first few regardless */ 74753873Simp break; 74853873Simp } 74953873Simp } 75053873Simp} 75153873Simp 75253873Simpstatic int 75353873Simppccard_print_child(device_t dev, device_t child) 75453873Simp{ 75566847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 75653873Simp struct resource_list *rl = &devi->resources; 75753873Simp int retval = 0; 75853873Simp 75953873Simp retval += bus_print_child_header(dev, child); 76053873Simp retval += printf(" at"); 76153873Simp 76253873Simp if (devi) { 76353873Simp pccard_print_resources(rl, "port", SYS_RES_IOPORT, 76453873Simp PCCARD_NPORT, "%#lx"); 76553873Simp pccard_print_resources(rl, "iomem", SYS_RES_MEMORY, 76653873Simp PCCARD_NMEM, "%#lx"); 76753873Simp pccard_print_resources(rl, "irq", SYS_RES_IRQ, PCCARD_NIRQ, 76853873Simp "%ld"); 76970715Sjon pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ, 77053873Simp "%ld"); 77167269Simp retval += printf(" function %d config %d", devi->fcn->number, 77267269Simp devi->fcn->cfe->number); 77353873Simp } 77453873Simp 77553873Simp retval += bus_print_child_footer(dev, child); 77653873Simp 77753873Simp return (retval); 77853873Simp} 77953873Simp 78053873Simpstatic int 78153873Simppccard_set_resource(device_t dev, device_t child, int type, int rid, 78253873Simp u_long start, u_long count) 78353873Simp{ 78466847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 78553873Simp struct resource_list *rl = &devi->resources; 78653873Simp 78753873Simp if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY 78853873Simp && type != SYS_RES_IRQ && type != SYS_RES_DRQ) 78974632Simp return (EINVAL); 79053873Simp if (rid < 0) 79174632Simp return (EINVAL); 79253873Simp if (type == SYS_RES_IOPORT && rid >= PCCARD_NPORT) 79374632Simp return (EINVAL); 79453873Simp if (type == SYS_RES_MEMORY && rid >= PCCARD_NMEM) 79574632Simp return (EINVAL); 79653873Simp if (type == SYS_RES_IRQ && rid >= PCCARD_NIRQ) 79774632Simp return (EINVAL); 79853873Simp if (type == SYS_RES_DRQ && rid >= PCCARD_NDRQ) 79974632Simp return (EINVAL); 80053873Simp 80153873Simp resource_list_add(rl, type, rid, start, start + count - 1, count); 80253873Simp 80374632Simp return (0); 80453873Simp} 80553873Simp 80653873Simpstatic int 80753873Simppccard_get_resource(device_t dev, device_t child, int type, int rid, 80853873Simp u_long *startp, u_long *countp) 80953873Simp{ 81066847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 81153873Simp struct resource_list *rl = &devi->resources; 81253873Simp struct resource_list_entry *rle; 81353873Simp 81453873Simp rle = resource_list_find(rl, type, rid); 81553873Simp if (!rle) 81674632Simp return (ENOENT); 81770715Sjon 81853873Simp if (startp) 81953873Simp *startp = rle->start; 82053873Simp if (countp) 82153873Simp *countp = rle->count; 82253873Simp 82374632Simp return (0); 82453873Simp} 82553873Simp 82653873Simpstatic void 82753873Simppccard_delete_resource(device_t dev, device_t child, int type, int rid) 82853873Simp{ 82966847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 83053873Simp struct resource_list *rl = &devi->resources; 83153873Simp resource_list_delete(rl, type, rid); 83253873Simp} 83353873Simp 83459193Simpstatic int 83559193Simppccard_set_res_flags(device_t dev, device_t child, int type, int rid, 83659193Simp u_int32_t flags) 83759193Simp{ 83874632Simp return (CARD_SET_RES_FLAGS(device_get_parent(dev), child, type, 83974632Simp rid, flags)); 84059193Simp} 84159193Simp 84259193Simpstatic int 84359193Simppccard_set_memory_offset(device_t dev, device_t child, int rid, 84470748Simp u_int32_t offset, u_int32_t *deltap) 84570715Sjon 84659193Simp{ 84774632Simp return (CARD_SET_MEMORY_OFFSET(device_get_parent(dev), child, rid, 84874632Simp offset, deltap)); 84959193Simp} 85059193Simp 85166058Simpstatic int 85266058Simppccard_read_ivar(device_t bus, device_t child, int which, u_char *result) 85366058Simp{ 85466847Simp struct pccard_ivar *devi = PCCARD_IVAR(child); 85566779Simp struct pccard_function *func = devi->fcn; 85666779Simp struct pccard_softc *sc = PCCARD_SOFTC(bus); 85766779Simp 85866058Simp /* PCCARD_IVAR_ETHADDR unhandled from oldcard */ 85966779Simp switch (which) { 86066779Simp default: 86166779Simp case PCCARD_IVAR_ETHADDR: 86266779Simp return (ENOENT); 86366779Simp break; 86466779Simp case PCCARD_IVAR_VENDOR: 86566779Simp *(u_int32_t *) result = sc->card.manufacturer; 86666779Simp break; 86766779Simp case PCCARD_IVAR_PRODUCT: 86866779Simp *(u_int32_t *) result = sc->card.product; 86966779Simp break; 87066779Simp case PCCARD_IVAR_FUNCTION_NUMBER: 87166847Simp if (!func) { 87266847Simp device_printf(bus, "No function number, bug!\n"); 87366847Simp return (ENOENT); 87466847Simp } 87566847Simp *(u_int32_t *) result = func->number; 87666779Simp break; 87766779Simp case PCCARD_IVAR_VENDOR_STR: 87866779Simp *(char **) result = sc->card.cis1_info[0]; 87966779Simp break; 88066779Simp case PCCARD_IVAR_PRODUCT_STR: 88166779Simp *(char **) result = sc->card.cis1_info[1]; 88266779Simp break; 88366779Simp case PCCARD_IVAR_CIS3_STR: 88466779Simp *(char **) result = sc->card.cis1_info[2]; 88566779Simp break; 88667167Simp case PCCARD_IVAR_CIS4_STR: 88767167Simp *(char **) result = sc->card.cis1_info[2]; 88867167Simp break; 88966779Simp } 89066779Simp return (0); 89166058Simp} 89266058Simp 89366779Simpstatic void 89466779Simppccard_driver_added(device_t dev, driver_t *driver) 89566779Simp{ 89667167Simp /* 89767167Simp * XXX eventually we need to attach stuff when we know we 89867167Simp * XXX have kids. For now we do nothing because we normally 89967167Simp * XXX add children ourselves. We don't want to necessarily 90067167Simp * XXX force a reprobe. 90167167Simp */ 90266779Simp} 90366058Simp 90467242Simpstatic struct resource * 90567242Simppccard_alloc_resource(device_t dev, device_t child, int type, int *rid, 90667242Simp u_long start, u_long end, u_long count, u_int flags) 90767242Simp{ 90870715Sjon struct resource_list_entry *rle = NULL; 90967242Simp 91070715Sjon /* XXX: This is an ugly way to fudge the resources. */ 91170715Sjon 91267242Simp if (device_get_parent(child) == dev) { 91370715Sjon struct pccard_ivar *devi = PCCARD_IVAR(child); 91470715Sjon struct resource_list *rl = &devi->resources; 91570715Sjon 91670715Sjon rle = resource_list_find(rl, type, *rid); 91767242Simp } 91870715Sjon 91970715Sjon if (rle != NULL) { 92070715Sjon if (flags & RF_ACTIVE) 92170715Sjon bus_activate_resource(dev, type, rle->rid, rle->res); 92270715Sjon return (rle->res); 92367269Simp } 92467242Simp return (bus_generic_alloc_resource(dev, child, type, rid, start, 92567242Simp end, count, flags)); 92667242Simp} 92767242Simp 92867242Simpstatic int 92967242Simppccard_release_resource(device_t dev, device_t child, int type, int rid, 93067242Simp struct resource *r) 93167242Simp{ 93270715Sjon struct resource_list_entry *rle = NULL; 93370715Sjon 93470715Sjon if (device_get_parent(child) == dev) { 93570715Sjon struct pccard_ivar *devi = PCCARD_IVAR(child); 93670715Sjon struct resource_list *rl = &devi->resources; 93770715Sjon 93870715Sjon rle = resource_list_find(rl, type, rid); 93970715Sjon } 94070715Sjon 94170715Sjon if (rle != NULL) { 94274632Simp return (bus_deactivate_resource(dev, type, rle->rid, rle->res)); 94370715Sjon } 94470715Sjon 94574632Simp return (bus_generic_release_resource(dev, child, type, rid, r)); 94667242Simp} 94767242Simp 94867242Simpstatic int 94967242Simppccard_activate_resource(device_t dev, device_t child, int type, int rid, 95067242Simp struct resource *r) 95167242Simp{ 95267269Simp /* XXX need to write to the COR to activate this for mf cards */ 95370715Sjon struct resource_list_entry *rle = NULL; 95470715Sjon 95570715Sjon if (device_get_parent(child) == dev) { 95670715Sjon struct pccard_ivar *devi = PCCARD_IVAR(child); 95770715Sjon struct resource_list *rl = &devi->resources; 95870715Sjon 95970715Sjon rle = resource_list_find(rl, type, rid); 96070715Sjon } 96170715Sjon 96270715Sjon if (rle != NULL) { 96370715Sjon return (bus_activate_resource(dev, type, rle->rid, rle->res)); 96470715Sjon } 96570715Sjon 96667242Simp return (bus_generic_activate_resource(dev, child, type, rid, r)); 96767242Simp} 96867242Simp 96967242Simpstatic int 97067242Simppccard_deactivate_resource(device_t dev, device_t child, int type, int rid, 97167242Simp struct resource *r) 97267242Simp{ 97367269Simp /* XXX need to write to the COR to deactivate this for mf cards */ 97470715Sjon struct resource_list_entry *rle = NULL; 97570715Sjon 97670715Sjon if (device_get_parent(child) == dev) { 97770715Sjon struct pccard_ivar *devi = PCCARD_IVAR(child); 97870715Sjon struct resource_list *rl = &devi->resources; 97970715Sjon 98070715Sjon rle = resource_list_find(rl, type, rid); 98170715Sjon } 98270715Sjon 98370715Sjon if (rle != NULL) { 98470715Sjon return (bus_deactivate_resource(dev, type, rle->rid, rle->res)); 98570715Sjon } 98670715Sjon 98767242Simp return (bus_generic_deactivate_resource(dev, child, type, rid, r)); 98867242Simp} 98967242Simp 99067333Simpstatic void 99167333Simppccard_child_detached(device_t parent, device_t dev) 99267333Simp{ 99367333Simp struct pccard_ivar *ivar = PCCARD_IVAR(dev); 99467333Simp 99567333Simp if (parent == device_get_parent(dev)) 99667333Simp free(ivar, M_DEVBUF); 99767333Simp} 99867333Simp 99970715Sjonstatic void 100070762Simppccard_intr(void *arg) 100170762Simp{ 100270762Simp struct pccard_softc *sc = (struct pccard_softc *) arg; 100370715Sjon struct pccard_function *pf; 100470762Simp STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { 100570715Sjon if (pf->intr_handler != NULL) { 100670715Sjon int reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS); 100770715Sjon if (reg & PCCARD_CCR_STATUS_INTR) { 100870715Sjon pccard_ccr_write(pf, PCCARD_CCR_STATUS, 100970762Simp reg & ~PCCARD_CCR_STATUS_INTR); 101070715Sjon pf->intr_handler(pf->intr_handler_arg); 101170715Sjon } 101270715Sjon } 101370715Sjon } 101470715Sjon} 101570715Sjon 101670715Sjonstatic int 101770762Simppccard_setup_intr(device_t dev, device_t child, struct resource *irq, 101870762Simp int flags, driver_intr_t *intr, void *arg, void **cookiep) 101970715Sjon{ 102070715Sjon struct pccard_ivar *ivar = PCCARD_IVAR(child); 102170715Sjon struct pccard_function *func = ivar->fcn; 102270715Sjon struct resource_list_entry *rle = NULL; 102370715Sjon struct pccard_softc *sc = device_get_softc(dev); 102470715Sjon 102570715Sjon if (func->intr_handler != NULL) 102670762Simp panic("Only one interrupt handler per function allowed\n"); 102770715Sjon 102870715Sjon rle = resource_list_find(&ivar->resources, SYS_RES_IRQ, 0); 102970715Sjon if (rle == NULL || rle->res != irq) 103070715Sjon panic("irq in setup_intr does not match allocated irq\n"); 103170715Sjon 103270715Sjon func->intr_handler = intr; 103370715Sjon func->intr_handler_arg = arg; 103470761Simp func->intr_handler_cookie = *cookiep = func; 103570715Sjon pccard_ccr_write(func, PCCARD_CCR_OPTION, 103670762Simp pccard_ccr_read(func, PCCARD_CCR_OPTION) | 103770762Simp PCCARD_CCR_OPTION_IREQ_ENABLE); 103870715Sjon 103970715Sjon if (sc->intr_handler_count++ == 0) { 104070715Sjon rle = resource_list_find(&ivar->resources, SYS_RES_IRQ, 0); 104170715Sjon if (rle == NULL) 104270715Sjon panic("No IRQ for pccard?"); 104370715Sjon 104470715Sjon bus_setup_intr(dev, rle->res, INTR_TYPE_TTY/* | INTR_FAST*/, 104570762Simp pccard_intr, sc, (void*)&sc->intr_handler_count); 104670715Sjon } 104774632Simp return (0); 104870715Sjon} 104970715Sjon 105070715Sjonstatic int 105170762Simppccard_teardown_intr(device_t dev, device_t child, struct resource *r, 105270762Simp void *cookie) 105370715Sjon{ 105470715Sjon struct pccard_ivar *ivar = PCCARD_IVAR(child); 105570715Sjon struct pccard_function *func = ivar->fcn; 105670715Sjon struct pccard_softc *sc = device_get_softc(dev); 105770715Sjon 105870715Sjon if (func->intr_handler_cookie != cookie) 105970715Sjon panic("pccard teardown of unknown interrupt handler\n"); 106070715Sjon 106170715Sjon func->intr_handler = NULL; 106270715Sjon func->intr_handler_arg = NULL; 106370715Sjon func->intr_handler_cookie = NULL; 106470715Sjon pccard_ccr_write(func, PCCARD_CCR_OPTION, 106570762Simp pccard_ccr_read(func, PCCARD_CCR_OPTION) & 106670762Simp ~PCCARD_CCR_OPTION_IREQ_ENABLE); 106770715Sjon 106870715Sjon if (--sc->intr_handler_count == 0) { 106970715Sjon struct resource_list_entry *rle = NULL; 107070715Sjon 107170715Sjon rle = resource_list_find(&ivar->resources, SYS_RES_IRQ, 0); 107270715Sjon if (rle == NULL) 107370715Sjon panic("No IRQ for pccard?"); 107470715Sjon 107570715Sjon bus_teardown_intr(dev, rle->res, &sc->intr_handler_count); 107670715Sjon } 107774632Simp return (0); 107870715Sjon} 107970715Sjon 108052506Simpstatic device_method_t pccard_methods[] = { 108152506Simp /* Device interface */ 108252506Simp DEVMETHOD(device_probe, pccard_probe), 108359193Simp DEVMETHOD(device_attach, pccard_attach), 108461788Simp DEVMETHOD(device_detach, bus_generic_detach), 108552506Simp DEVMETHOD(device_shutdown, bus_generic_shutdown), 108652506Simp DEVMETHOD(device_suspend, bus_generic_suspend), 108752506Simp DEVMETHOD(device_resume, bus_generic_resume), 108852506Simp 108952506Simp /* Bus interface */ 109052506Simp DEVMETHOD(bus_print_child, pccard_print_child), 109166779Simp DEVMETHOD(bus_driver_added, pccard_driver_added), 109267333Simp DEVMETHOD(bus_child_detached, pccard_child_detached), 109367242Simp DEVMETHOD(bus_alloc_resource, pccard_alloc_resource), 109467242Simp DEVMETHOD(bus_release_resource, pccard_release_resource), 109567242Simp DEVMETHOD(bus_activate_resource, pccard_activate_resource), 109667242Simp DEVMETHOD(bus_deactivate_resource, pccard_deactivate_resource), 109770715Sjon DEVMETHOD(bus_setup_intr, pccard_setup_intr), 109870715Sjon DEVMETHOD(bus_teardown_intr, pccard_teardown_intr), 109952506Simp DEVMETHOD(bus_set_resource, pccard_set_resource), 110052506Simp DEVMETHOD(bus_get_resource, pccard_get_resource), 110152506Simp DEVMETHOD(bus_delete_resource, pccard_delete_resource), 110266058Simp DEVMETHOD(bus_read_ivar, pccard_read_ivar), 110352506Simp 110459193Simp /* Card Interface */ 110559193Simp DEVMETHOD(card_set_res_flags, pccard_set_res_flags), 110659193Simp DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset), 110759193Simp DEVMETHOD(card_get_type, pccard_card_gettype), 110859193Simp DEVMETHOD(card_attach_card, pccard_attach_card), 110959193Simp DEVMETHOD(card_detach_card, pccard_detach_card), 111074636Simp DEVMETHOD(card_compat_do_probe, pccard_compat_do_probe), 111174636Simp DEVMETHOD(card_compat_do_attach, pccard_compat_do_attach), 111259193Simp 111352506Simp { 0, 0 } 111452506Simp}; 111552506Simp 111652506Simpstatic driver_t pccard_driver = { 111752506Simp "pccard", 111852506Simp pccard_methods, 111964850Simp sizeof(struct pccard_softc) 112052506Simp}; 112152506Simp 112252506Simpdevclass_t pccard_devclass; 112352506Simp 112453873SimpDRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0); 112552506SimpDRIVER_MODULE(pccard, pc98pcic, pccard_driver, pccard_devclass, 0, 0); 112652506SimpDRIVER_MODULE(pccard, pccbb, pccard_driver, pccard_devclass, 0, 0); 112753873SimpDRIVER_MODULE(pccard, tcic, pccard_driver, pccard_devclass, 0, 0); 112864927SimpMODULE_VERSION(pccard, 1); 112970715Sjon/*MODULE_DEPEND(pccard, pcic, 1, 1, 1);*/ 1130