root/dev/pcmcia/wdc_pcmcia.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wdc_pcmcia_disk_device_interface_callback
  2. wdc_pcmcia_disk_device_interface
  3. wdc_pcmcia_lookup
  4. wdc_pcmcia_match
  5. wdc_pcmcia_attach
  6. wdc_pcmcia_detach
  7. wdc_pcmcia_activate
  8. wdc_pcmcia_enable

    1 /*      $OpenBSD: wdc_pcmcia.c,v 1.17 2006/04/20 20:31:13 miod Exp $    */
    2 /*      $NetBSD: wdc_pcmcia.c,v 1.19 1999/02/19 21:49:43 abs Exp $ */
    3 
    4 /*-
    5  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Charles M. Hannum, by Onno van der Linden and by Manuel Bouyer.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *        This product includes software developed by the NetBSD
   22  *        Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/kernel.h>
   43 #include <sys/conf.h>
   44 #include <sys/file.h>
   45 #include <sys/stat.h>
   46 #include <sys/ioctl.h>
   47 #include <sys/buf.h>
   48 #include <sys/uio.h>
   49 #include <sys/malloc.h>
   50 #include <sys/device.h>
   51 #include <sys/disklabel.h>
   52 #include <sys/disk.h>
   53 #include <sys/syslog.h>
   54 #include <sys/proc.h>
   55 
   56 #include <uvm/uvm_extern.h>
   57 
   58 #include <machine/cpu.h>
   59 #include <machine/intr.h>
   60 #include <machine/bus.h>
   61 
   62 #include <dev/pcmcia/pcmciareg.h>
   63 #include <dev/pcmcia/pcmciavar.h>
   64 #include <dev/pcmcia/pcmciadevs.h>
   65 
   66 #include <dev/ata/atavar.h>
   67 #include <dev/ic/wdcvar.h>
   68 
   69 #define WDC_PCMCIA_REG_NPORTS      8
   70 #define WDC_PCMCIA_AUXREG_OFFSET   (WDC_PCMCIA_REG_NPORTS + 6)
   71 #define WDC_PCMCIA_AUXREG_NPORTS   2
   72 
   73 struct wdc_pcmcia_softc {
   74         struct wdc_softc sc_wdcdev;
   75         struct channel_softc *wdc_chanptr;
   76         struct channel_softc wdc_channel;
   77         struct pcmcia_io_handle sc_pioh;
   78         struct pcmcia_io_handle sc_auxpioh;
   79         int sc_iowindow;
   80         int sc_auxiowindow;
   81         void *sc_ih;
   82         struct pcmcia_function *sc_pf;
   83         int sc_flags;
   84 #define WDC_PCMCIA_ATTACH       0x0001
   85 };
   86 
   87 static int wdc_pcmcia_match(struct device *, void *, void *);
   88 static void wdc_pcmcia_attach(struct device *, struct device *, void *);
   89 int    wdc_pcmcia_detach(struct device *, int);
   90 int    wdc_pcmcia_activate(struct device *, enum devact);
   91 
   92 struct cfattach wdc_pcmcia_ca = {
   93         sizeof(struct wdc_pcmcia_softc), wdc_pcmcia_match, wdc_pcmcia_attach,
   94         wdc_pcmcia_detach, wdc_pcmcia_activate
   95 };
   96 
   97 struct wdc_pcmcia_product {
   98         u_int16_t       wpp_vendor;     /* vendor ID */
   99         u_int16_t       wpp_product;    /* product ID */
  100         int             wpp_quirk_flag; /* Quirk flags */
  101 #define WDC_PCMCIA_FORCE_16BIT_IO       0x01 /* Don't use PCMCIA_WIDTH_AUTO */
  102 #define WDC_PCMCIA_NO_EXTRA_RESETS      0x02 /* Only reset ctrl once */
  103         const char      *wpp_cis_info[4];       /* XXX necessary? */
  104 } wdc_pcmcia_pr[] = {
  105 
  106         { /* PCMCIA_VENDOR_DIGITAL XXX */ 0x0100,
  107           PCMCIA_PRODUCT_DIGITAL_MOBILE_MEDIA_CDROM,
  108           0, { NULL, "Digital Mobile Media CD-ROM", NULL, NULL }, },
  109 
  110         { PCMCIA_VENDOR_IBM, PCMCIA_PRODUCT_IBM_PORTABLE_CDROM,
  111           0, { NULL, "Portable CD-ROM Drive", NULL, NULL }, },
  112 
  113         { PCMCIA_VENDOR_HAGIWARASYSCOM, PCMCIA_PRODUCT_INVALID, /* XXX */
  114           WDC_PCMCIA_FORCE_16BIT_IO, { NULL, NULL, NULL, NULL }, },
  115 
  116         /* The TEAC IDE/Card II is used on the Sony Vaio */
  117         { PCMCIA_VENDOR_TEAC, PCMCIA_PRODUCT_TEAC_IDECARDII,
  118           WDC_PCMCIA_NO_EXTRA_RESETS, PCMCIA_CIS_TEAC_IDECARDII },
  119 
  120         /*
  121          * EXP IDE/ATAPI DVD Card use with some DVD players.
  122          * Does not have a vendor ID or product ID.
  123          */
  124         { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID,
  125           0, PCMCIA_CIS_EXP_EXPMULTIMEDIA },
  126 
  127         /* Mobile Dock 2, which doesn't have vendor ID nor product ID */
  128         { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID,
  129           0, PCMCIA_CIS_SHUTTLE_IDE_ATAPI },
  130 
  131         /* Archos MiniCD */
  132         { PCMCIA_VENDOR_ARCHOS, PCMCIA_PRODUCT_ARCHOS_ARC_ATAPI,
  133           0, PCMCIA_CIS_ARCHOS_ARC_ATAPI },
  134 };
  135 
  136 struct wdc_pcmcia_disk_device_interface_args {
  137         int ddi_type;           /* interface type */
  138         int ddi_reqfn;          /* function we are requesting iftype */
  139         int ddi_curfn;          /* function we are currently parsing in CIS */
  140 };
  141 
  142 int     wdc_pcmcia_disk_device_interface_callback(struct pcmcia_tuple *,
  143             void *);
  144 int     wdc_pcmcia_disk_device_interface(struct pcmcia_function *);
  145 struct wdc_pcmcia_product *
  146         wdc_pcmcia_lookup(struct pcmcia_attach_args *);
  147 
  148 int     wdc_pcmcia_enable(void *, int);
  149 
  150 int
  151 wdc_pcmcia_disk_device_interface_callback(tuple, arg)
  152         struct pcmcia_tuple *tuple;
  153         void *arg;
  154 {
  155         struct wdc_pcmcia_disk_device_interface_args *ddi = arg;
  156 
  157         switch (tuple->code) {
  158         case PCMCIA_CISTPL_FUNCID:
  159                 ddi->ddi_curfn++;
  160                 break;
  161 
  162         case PCMCIA_CISTPL_FUNCE:
  163                 if (ddi->ddi_reqfn != ddi->ddi_curfn)
  164                         break;
  165 
  166                 /* subcode (disk device interface), data (interface type) */
  167                 if (tuple->length < 2)
  168                         break;
  169 
  170                 /* check type */
  171                 if (pcmcia_tuple_read_1(tuple, 0) !=
  172                     PCMCIA_TPLFE_TYPE_DISK_DEVICE_INTERFACE)
  173                         break;
  174 
  175                 ddi->ddi_type = pcmcia_tuple_read_1(tuple, 1);
  176                 return (1);
  177         }
  178         return (0);
  179 }
  180 
  181 int
  182 wdc_pcmcia_disk_device_interface(pf)
  183         struct pcmcia_function *pf;
  184 {
  185         struct wdc_pcmcia_disk_device_interface_args ddi;
  186 
  187         ddi.ddi_reqfn = pf->number;
  188         ddi.ddi_curfn = -1;
  189         if (pcmcia_scan_cis((struct device *)pf->sc,
  190             wdc_pcmcia_disk_device_interface_callback, &ddi) > 0)
  191                 return (ddi.ddi_type);
  192         else
  193                 return (-1);
  194 }
  195 
  196 struct wdc_pcmcia_product *
  197 wdc_pcmcia_lookup(pa)
  198         struct pcmcia_attach_args *pa;
  199 {
  200         struct wdc_pcmcia_product *wpp;
  201         int i, cis_match;
  202 
  203         for (wpp = wdc_pcmcia_pr;
  204             wpp < &wdc_pcmcia_pr[sizeof(wdc_pcmcia_pr)/sizeof(wdc_pcmcia_pr[0])];
  205             wpp++)
  206                 if ((wpp->wpp_vendor == PCMCIA_VENDOR_INVALID ||
  207                      pa->manufacturer == wpp->wpp_vendor) &&
  208                     (wpp->wpp_product == PCMCIA_PRODUCT_INVALID ||
  209                      pa->product == wpp->wpp_product)) {
  210                         cis_match = 1;
  211                         for (i = 0; i < 4; i++) {
  212                                 if (!(wpp->wpp_cis_info[i] == NULL ||
  213                                       (pa->card->cis1_info[i] != NULL &&
  214                                        strcmp(pa->card->cis1_info[i],
  215                                               wpp->wpp_cis_info[i]) == 0)))
  216                                         cis_match = 0;
  217                         }
  218                         if (cis_match)
  219                                 return (wpp);
  220                 }
  221 
  222         return (NULL);
  223 }
  224 
  225 static int
  226 wdc_pcmcia_match(parent, match, aux)
  227         struct device *parent;
  228         void *match, *aux;
  229 {
  230         struct pcmcia_attach_args *pa = aux;
  231         struct pcmcia_softc *sc;
  232         int iftype;
  233 
  234         if (wdc_pcmcia_lookup(pa) != NULL)
  235                 return (1);
  236 
  237         if (pa->pf->function == PCMCIA_FUNCTION_DISK) {
  238                 sc = pa->pf->sc;
  239 
  240                 pcmcia_chip_socket_enable(sc->pct, sc->pch);
  241                 iftype = wdc_pcmcia_disk_device_interface(pa->pf);
  242                 pcmcia_chip_socket_disable(sc->pct, sc->pch);
  243 
  244                 if (iftype == PCMCIA_TPLFE_DDI_PCCARD_ATA)
  245                         return (1);
  246         }
  247 
  248         return (0);
  249 }
  250 
  251 static void
  252 wdc_pcmcia_attach(parent, self, aux)
  253         struct device *parent;
  254         struct device *self;
  255         void *aux;
  256 {
  257         struct wdc_pcmcia_softc *sc = (void *)self;
  258         struct pcmcia_attach_args *pa = aux;
  259         struct pcmcia_config_entry *cfe;
  260         struct wdc_pcmcia_product *wpp;
  261         const char *intrstr;
  262         int quirks;
  263 
  264         sc->sc_pf = pa->pf;
  265 
  266         for (cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head); cfe != NULL;
  267             cfe = SIMPLEQ_NEXT(cfe, cfe_list)) {
  268                 if (cfe->num_iospace != 1 && cfe->num_iospace != 2)
  269                         continue;
  270 
  271                 if (pcmcia_io_alloc(pa->pf, cfe->iospace[0].start,
  272                     cfe->iospace[0].length,
  273                     cfe->iospace[0].start == 0 ? cfe->iospace[0].length : 0,
  274                     &sc->sc_pioh))
  275                         continue;
  276 
  277                 if (cfe->num_iospace == 2) {
  278                         if (!pcmcia_io_alloc(pa->pf, cfe->iospace[1].start,
  279                             cfe->iospace[1].length, 0, &sc->sc_auxpioh))
  280                                 break;
  281                 } else /* num_iospace == 1 */ {
  282                         sc->sc_auxpioh.iot = sc->sc_pioh.iot;
  283                         if (!bus_space_subregion(sc->sc_pioh.iot,
  284                             sc->sc_pioh.ioh, WDC_PCMCIA_AUXREG_OFFSET,
  285                             WDC_PCMCIA_AUXREG_NPORTS, &sc->sc_auxpioh.ioh))
  286                                 break;
  287                 }
  288                 pcmcia_io_free(pa->pf, &sc->sc_pioh);
  289         }
  290 
  291         if (cfe == NULL) {
  292                 printf(": can't handle card info\n");
  293                 goto no_config_entry;
  294         }
  295 
  296         /* Enable the card. */
  297         pcmcia_function_init(pa->pf, cfe);
  298         if (pcmcia_function_enable(pa->pf)) {
  299                 printf(": function enable failed\n");
  300                 goto enable_failed;
  301         }
  302 
  303         /*
  304          * XXX  DEC Mobile Media CDROM is not yet tested whether it works
  305          * XXX  with PCMCIA_WIDTH_IO16.  HAGIWARA SYS-COM HPC-CF32 doesn't
  306          * XXX  work with PCMCIA_WIDTH_AUTO.
  307          * XXX  CANON FC-8M (SANDISK SDCFB 8M) works for both _AUTO and IO16.
  308          * XXX  So, here is temporary work around.
  309          */
  310         wpp = wdc_pcmcia_lookup(pa);
  311         if (wpp != NULL)
  312                 quirks = wpp->wpp_quirk_flag;
  313         else
  314                 quirks = 0;
  315 
  316         if (pcmcia_io_map(pa->pf, quirks & WDC_PCMCIA_FORCE_16BIT_IO ?
  317             PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_AUTO, 0,
  318             sc->sc_pioh.size, &sc->sc_pioh, &sc->sc_iowindow)) {
  319                 printf(": can't map first I/O space\n");
  320                 goto iomap_failed;
  321         } 
  322 
  323         /*
  324          * Currently, # of iospace is 1 except DIGITAL Mobile Media CD-ROM.
  325          * So whether the work around like above is necessary or not
  326          * is unknown.  XXX.
  327          */
  328         if (cfe->num_iospace <= 1)
  329                 sc->sc_auxiowindow = -1;
  330         else if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_AUTO, 0,
  331             sc->sc_auxpioh.size, &sc->sc_auxpioh, &sc->sc_auxiowindow)) {
  332                 printf(": can't map second I/O space\n");
  333                 goto iomapaux_failed;
  334         }
  335 
  336         printf(" port 0x%lx/%lu",
  337             sc->sc_pioh.addr, (u_long)sc->sc_pioh.size);
  338         if (cfe->num_iospace > 1 && sc->sc_auxpioh.size > 0)
  339                 printf(",0x%lx/%lu",
  340                     sc->sc_auxpioh.addr, (u_long)sc->sc_auxpioh.size);
  341 
  342         sc->wdc_channel.cmd_iot = sc->sc_pioh.iot;
  343         sc->wdc_channel.cmd_ioh = sc->sc_pioh.ioh;
  344         sc->wdc_channel.ctl_iot = sc->sc_auxpioh.iot;
  345         sc->wdc_channel.ctl_ioh = sc->sc_auxpioh.ioh;
  346         sc->wdc_channel.data32iot = sc->wdc_channel.cmd_iot;
  347         sc->wdc_channel.data32ioh = sc->wdc_channel.cmd_ioh;
  348         sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32;
  349         sc->sc_wdcdev.PIO_cap = 0;
  350         sc->wdc_chanptr = &sc->wdc_channel;
  351         sc->sc_wdcdev.channels = &sc->wdc_chanptr;
  352         sc->sc_wdcdev.nchannels = 1;
  353         sc->wdc_channel.channel = 0;
  354         sc->wdc_channel.wdc = &sc->sc_wdcdev;
  355         sc->wdc_channel.ch_queue = malloc(sizeof(struct channel_queue),
  356             M_DEVBUF, M_NOWAIT);
  357         if (sc->wdc_channel.ch_queue == NULL) {
  358                 printf("can't allocate memory for command queue\n");
  359                 goto ch_queue_alloc_failed;
  360         }
  361         if (quirks & WDC_PCMCIA_NO_EXTRA_RESETS)
  362                 sc->sc_wdcdev.cap |= WDC_CAPABILITY_NO_EXTRA_RESETS;
  363 
  364 #ifdef notyet
  365         /* We can enable and disable the controller. */
  366         sc->sc_wdcdev.sc_atapi_adapter.scsipi_enable = wdc_pcmcia_enable;
  367 
  368         /*
  369          * Disable the pcmcia function now; wdcattach() will enable
  370          * us again as it adds references to probe for children.
  371          */
  372         pcmcia_function_disable(pa->pf);
  373 #else
  374         /* Establish the interrupt handler. */
  375         sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO, wdcintr,
  376             &sc->wdc_channel, sc->sc_wdcdev.sc_dev.dv_xname);
  377         intrstr = pcmcia_intr_string(sc->sc_pf, sc->sc_ih);
  378         if (*intrstr)
  379                 printf(": %s", intrstr);
  380 #endif
  381 
  382         printf("\n");
  383 
  384         sc->sc_flags |= WDC_PCMCIA_ATTACH;
  385         wdcattach(&sc->wdc_channel);
  386         wdc_print_current_modes(&sc->wdc_channel);
  387         sc->sc_flags &= ~WDC_PCMCIA_ATTACH;
  388         return;
  389 
  390  ch_queue_alloc_failed:
  391         /* Unmap our aux i/o window. */
  392         if (sc->sc_auxiowindow != -1)
  393                 pcmcia_io_unmap(sc->sc_pf, sc->sc_auxiowindow);
  394 
  395  iomapaux_failed:
  396         /* Unmap our i/o window. */
  397         pcmcia_io_unmap(sc->sc_pf, sc->sc_iowindow);
  398 
  399  iomap_failed:
  400         /* Disable the function */
  401         pcmcia_function_disable(sc->sc_pf);
  402 
  403  enable_failed:
  404         /* Unmap our i/o space. */
  405         pcmcia_io_free(sc->sc_pf, &sc->sc_pioh);
  406         if (cfe->num_iospace == 2)
  407                 pcmcia_io_free(sc->sc_pf, &sc->sc_auxpioh);
  408 
  409  no_config_entry:
  410         sc->sc_iowindow = -1;
  411 }
  412 
  413 int
  414 wdc_pcmcia_detach(self, flags)
  415         struct device *self;
  416         int  flags;
  417 {
  418         struct wdc_pcmcia_softc *sc = (struct wdc_pcmcia_softc *)self;
  419         int error;
  420 
  421         if (sc->sc_iowindow == -1)
  422                 /* Nothing to detach */
  423                 return (0);
  424         
  425         if ((error = wdcdetach(&sc->wdc_channel, flags)) != 0) 
  426                 return (error);
  427 
  428         if (sc->wdc_channel.ch_queue != NULL)
  429                 free(sc->wdc_channel.ch_queue, M_DEVBUF);
  430 
  431         /* Unmap our i/o window and i/o space. */
  432         pcmcia_io_unmap(sc->sc_pf, sc->sc_iowindow);
  433         pcmcia_io_free(sc->sc_pf, &sc->sc_pioh);
  434         if (sc->sc_auxiowindow != -1) {
  435                 pcmcia_io_unmap(sc->sc_pf, sc->sc_auxiowindow);
  436                 pcmcia_io_free(sc->sc_pf, &sc->sc_auxpioh);
  437         }
  438 
  439         return (0);
  440 }
  441 
  442 int
  443 wdc_pcmcia_activate(self, act)
  444         struct device *self;
  445         enum devact act;
  446 {
  447         struct wdc_pcmcia_softc *sc = (struct wdc_pcmcia_softc *)self;
  448         int rv = 0, s;
  449 
  450         s = splbio();
  451         switch (act) {
  452         case DVACT_ACTIVATE:
  453                 if (pcmcia_function_enable(sc->sc_pf)) {
  454                         printf("%s: couldn't enable PCMCIA function\n",
  455                             sc->sc_wdcdev.sc_dev.dv_xname);
  456                         rv = EIO;
  457                         break;
  458                 }
  459 
  460                 sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO, 
  461                     wdcintr, &sc->wdc_channel, sc->sc_wdcdev.sc_dev.dv_xname);
  462                 if (sc->sc_ih == NULL) {
  463                         printf("%s: "
  464                             "couldn't establish interrupt handler\n",
  465                             sc->sc_wdcdev.sc_dev.dv_xname);
  466                         pcmcia_function_disable(sc->sc_pf);
  467                         rv = EIO;
  468                         break;
  469                 }
  470 
  471                 wdcreset(&sc->wdc_channel, VERBOSE);
  472                 rv = wdcactivate(self, act);
  473                 break;
  474 
  475         case DVACT_DEACTIVATE:
  476                 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
  477                 pcmcia_function_disable(sc->sc_pf);
  478                 rv = wdcactivate(self, act);
  479                 break;
  480         }
  481         splx(s);
  482         return (rv);
  483 }
  484 
  485 #if 0
  486 int
  487 wdc_pcmcia_enable(arg, onoff)
  488         void *arg;
  489         int onoff;
  490 {
  491         struct wdc_pcmcia_softc *sc = arg;
  492 
  493         if (onoff) {
  494                 if ((sc->sc_flags & WDC_PCMCIA_ATTACH) == 0) {
  495                         if (pcmcia_function_enable(sc->sc_pf)) {
  496                                 printf("%s: couldn't enable PCMCIA function\n",
  497                                     sc->sc_wdcdev.sc_dev.dv_xname);
  498                                 return (EIO);
  499                         }
  500 
  501                         sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO, 
  502                             wdcintr, &sc->wdc_channel, sc->sc_dev.dv_xname);
  503                         if (sc->sc_ih == NULL) {
  504                                 printf("%s: "
  505                                     "couldn't establish interrupt handler\n",
  506                                     sc->sc_wdcdev.sc_dev.dv_xname);
  507                                 pcmcia_function_disable(sc->sc_pf);
  508                                 return (EIO);
  509                         }
  510 
  511                         wdcreset(&sc->wdc_channel, VERBOSE);
  512                 }
  513         } else {
  514                 if ((sc->sc_flags & WDC_PCMCIA_ATTACH) == 0)
  515                         pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
  516                 pcmcia_function_disable(sc->sc_pf);
  517         }
  518 
  519         return (0);
  520 }
  521 #endif

/* [<][>][^][v][top][bottom][index][help] */