The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ichwd/ichwd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2004 Texas A&M University
    3  * All rights reserved.
    4  *
    5  * Developer: Wm. Daryl Hawkins
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 /*
   30  * Intel ICH Watchdog Timer (WDT) driver
   31  *
   32  * Originally developed by Wm. Daryl Hawkins of Texas A&M
   33  * Heavily modified by <des@FreeBSD.org>
   34  *
   35  * This is a tricky one.  The ICH WDT can't be treated as a regular PCI
   36  * device as it's actually an integrated function of the ICH LPC interface
   37  * bridge.  Detection is also awkward, because we can only infer the
   38  * presence of the watchdog timer from the fact that the machine has an
   39  * ICH chipset, or, on ACPI 2.x systems, by the presence of the 'WDDT'
   40  * ACPI table (although this driver does not support the ACPI detection
   41  * method).
   42  *
   43  * There is one slight problem on non-ACPI or ACPI 1.x systems: we have no
   44  * way of knowing if the WDT is permanently disabled (either by the BIOS
   45  * or in hardware).
   46  *
   47  * The WDT is programmed through I/O registers in the ACPI I/O space.
   48  * Intel swears it's always at offset 0x60, so we use that.
   49  *
   50  * For details about the ICH WDT, see Intel Application Note AP-725
   51  * (document no. 292273-001).  The WDT is also described in the individual
   52  * chipset datasheets, e.g. Intel82801EB ICH5 / 82801ER ICH5R Datasheet
   53  * (document no. 252516-001) sections 9.10 and 9.11.
   54  *
   55  * ICH6/7/8 support by Takeharu KATO <takeharu1219@ybb.ne.jp>
   56  */
   57 
   58 #include <sys/cdefs.h>
   59 __FBSDID("$FreeBSD$");
   60 
   61 #include <sys/param.h>
   62 #include <sys/kernel.h>
   63 #include <sys/module.h>
   64 #include <sys/systm.h>
   65 #include <sys/bus.h>
   66 #include <machine/bus.h>
   67 #include <sys/rman.h>
   68 #include <machine/resource.h>
   69 #include <sys/watchdog.h>
   70 
   71 #include <dev/pci/pcivar.h>
   72 
   73 #include <dev/ichwd/ichwd.h>
   74 
   75 static struct ichwd_device ichwd_devices[] = {
   76         { DEVICEID_82801AA,  "Intel 82801AA watchdog timer",    1 },
   77         { DEVICEID_82801AB,  "Intel 82801AB watchdog timer",    1 },
   78         { DEVICEID_82801BA,  "Intel 82801BA watchdog timer",    2 },
   79         { DEVICEID_82801BAM, "Intel 82801BAM watchdog timer",   2 },
   80         { DEVICEID_82801CA,  "Intel 82801CA watchdog timer",    3 },
   81         { DEVICEID_82801CAM, "Intel 82801CAM watchdog timer",   3 },
   82         { DEVICEID_82801DB,  "Intel 82801DB watchdog timer",    4 },
   83         { DEVICEID_82801DBM, "Intel 82801DBM watchdog timer",   4 },
   84         { DEVICEID_82801E,   "Intel 82801E watchdog timer",     5 },
   85         { DEVICEID_82801EB,  "Intel 82801EB watchdog timer",    5 },
   86         { DEVICEID_82801EBR, "Intel 82801EB/ER watchdog timer", 5 },
   87         { DEVICEID_6300ESB,  "Intel 6300ESB watchdog timer",    5 },
   88         { DEVICEID_82801FBR, "Intel 82801FB/FR watchdog timer", 6 },
   89         { DEVICEID_ICH6M,    "Intel ICH6M watchdog timer",      6 },
   90         { DEVICEID_ICH6W,    "Intel ICH6W watchdog timer",      6 },
   91         { DEVICEID_ICH7,     "Intel ICH7 watchdog timer",       7 },
   92         { DEVICEID_ICH7DH,   "Intel ICH7DH watchdog timer",     7 },
   93         { DEVICEID_ICH7M,    "Intel ICH7M watchdog timer",      7 },
   94         { DEVICEID_ICH7MDH,  "Intel ICH7MDH watchdog timer",    7 },
   95         { DEVICEID_ICH8,     "Intel ICH8 watchdog timer",       8 },
   96         { DEVICEID_ICH8DH,   "Intel ICH8DH watchdog timer",     8 },
   97         { DEVICEID_ICH8DO,   "Intel ICH8DO watchdog timer",     8 },
   98         { DEVICEID_ICH8M,    "Intel ICH8M watchdog timer",      8 },
   99         { DEVICEID_ICH8ME,   "Intel ICH8M-E watchdog timer",    8 },
  100         { DEVICEID_63XXESB,  "Intel 63XXESB watchdog timer",    8 },
  101         { DEVICEID_ICH9,     "Intel ICH9 watchdog timer",       9 },
  102         { DEVICEID_ICH9DH,   "Intel ICH9DH watchdog timer",     9 },
  103         { DEVICEID_ICH9DO,   "Intel ICH9DO watchdog timer",     9 },
  104         { DEVICEID_ICH9M,    "Intel ICH9M watchdog timer",      9 },
  105         { DEVICEID_ICH9ME,   "Intel ICH9M-E watchdog timer",    9 },
  106         { DEVICEID_ICH9R,    "Intel ICH9R watchdog timer",      9 },
  107         { DEVICEID_ICH10,    "Intel ICH10 watchdog timer",      10 },
  108         { DEVICEID_ICH10D,   "Intel ICH10D watchdog timer",     10 },
  109         { DEVICEID_ICH10DO,  "Intel ICH10DO watchdog timer",    10 },
  110         { DEVICEID_ICH10R,   "Intel ICH10R watchdog timer",     10 },
  111         { 0, NULL, 0 },
  112 };
  113 
  114 static devclass_t ichwd_devclass;
  115 
  116 #define ichwd_read_tco_1(sc, off) \
  117         bus_space_read_1((sc)->tco_bst, (sc)->tco_bsh, (off))
  118 #define ichwd_read_tco_2(sc, off) \
  119         bus_space_read_2((sc)->tco_bst, (sc)->tco_bsh, (off))
  120 #define ichwd_read_tco_4(sc, off) \
  121         bus_space_read_4((sc)->tco_bst, (sc)->tco_bsh, (off))
  122 #define ichwd_read_smi_4(sc, off) \
  123         bus_space_read_4((sc)->smi_bst, (sc)->smi_bsh, (off))
  124 #define ichwd_read_gcs_4(sc, off) \
  125         bus_space_read_4((sc)->gcs_bst, (sc)->gcs_bsh, (off))
  126 
  127 #define ichwd_write_tco_1(sc, off, val) \
  128         bus_space_write_1((sc)->tco_bst, (sc)->tco_bsh, (off), (val))
  129 #define ichwd_write_tco_2(sc, off, val) \
  130         bus_space_write_2((sc)->tco_bst, (sc)->tco_bsh, (off), (val))
  131 #define ichwd_write_tco_4(sc, off, val) \
  132         bus_space_write_4((sc)->tco_bst, (sc)->tco_bsh, (off), (val))
  133 #define ichwd_write_smi_4(sc, off, val) \
  134         bus_space_write_4((sc)->smi_bst, (sc)->smi_bsh, (off), (val))
  135 #define ichwd_write_gcs_4(sc, off, val) \
  136         bus_space_write_4((sc)->gcs_bst, (sc)->gcs_bsh, (off), (val))
  137 
  138 #define ichwd_verbose_printf(dev, ...) \
  139         do {                                            \
  140                 if (bootverbose)                        \
  141                         device_printf(dev, __VA_ARGS__);\
  142         } while (0)
  143 
  144 static __inline void
  145 ichwd_intr_enable(struct ichwd_softc *sc)
  146 {
  147         ichwd_write_smi_4(sc, SMI_EN, ichwd_read_smi_4(sc, SMI_EN) & ~SMI_TCO_EN);
  148 }
  149 
  150 static __inline void
  151 ichwd_intr_disable(struct ichwd_softc *sc)
  152 {
  153         ichwd_write_smi_4(sc, SMI_EN, ichwd_read_smi_4(sc, SMI_EN) | SMI_TCO_EN);
  154 }
  155 
  156 static __inline void
  157 ichwd_sts_reset(struct ichwd_softc *sc)
  158 {
  159         ichwd_write_tco_2(sc, TCO1_STS, TCO_TIMEOUT);
  160         ichwd_write_tco_2(sc, TCO2_STS, TCO_BOOT_STS);
  161         ichwd_write_tco_2(sc, TCO2_STS, TCO_SECOND_TO_STS);
  162 }
  163 
  164 static __inline void
  165 ichwd_tmr_enable(struct ichwd_softc *sc)
  166 {
  167         uint16_t cnt;
  168 
  169         cnt = ichwd_read_tco_2(sc, TCO1_CNT) & TCO_CNT_PRESERVE;
  170         ichwd_write_tco_2(sc, TCO1_CNT, cnt & ~TCO_TMR_HALT);
  171         sc->active = 1;
  172         ichwd_verbose_printf(sc->device, "timer enabled\n");
  173 }
  174 
  175 static __inline void
  176 ichwd_tmr_disable(struct ichwd_softc *sc)
  177 {
  178         uint16_t cnt;
  179 
  180         cnt = ichwd_read_tco_2(sc, TCO1_CNT) & TCO_CNT_PRESERVE;
  181         ichwd_write_tco_2(sc, TCO1_CNT, cnt | TCO_TMR_HALT);
  182         sc->active = 0;
  183         ichwd_verbose_printf(sc->device, "timer disabled\n");
  184 }
  185 
  186 static __inline void
  187 ichwd_tmr_reload(struct ichwd_softc *sc)
  188 {
  189         if (sc->ich_version <= 5)
  190                 ichwd_write_tco_1(sc, TCO_RLD, 1);
  191         else
  192                 ichwd_write_tco_2(sc, TCO_RLD, 1);
  193 
  194         ichwd_verbose_printf(sc->device, "timer reloaded\n");
  195 }
  196 
  197 static __inline void
  198 ichwd_tmr_set(struct ichwd_softc *sc, unsigned int timeout)
  199 {
  200 
  201         /*
  202          * If the datasheets are to be believed, the minimum value
  203          * actually varies from chipset to chipset - 4 for ICH5 and 2 for
  204          * all other chipsets.  I suspect this is a bug in the ICH5
  205          * datasheet and that the minimum is uniformly 2, but I'd rather
  206          * err on the side of caution.
  207          */
  208         if (timeout < 4)
  209                 timeout = 4;
  210 
  211         if (sc->ich_version <= 5) {
  212                 uint8_t tmr_val8 = ichwd_read_tco_1(sc, TCO_TMR1);
  213 
  214                 tmr_val8 &= 0xc0;
  215                 if (timeout > 0xbf)
  216                         timeout = 0xbf;
  217                 tmr_val8 |= timeout;
  218                 ichwd_write_tco_1(sc, TCO_TMR1, tmr_val8);
  219         } else {
  220                 uint16_t tmr_val16 = ichwd_read_tco_2(sc, TCO_TMR2);
  221 
  222                 tmr_val16 &= 0xfc00;
  223                 if (timeout > 0x0bff)
  224                         timeout = 0x0bff;
  225                 tmr_val16 |= timeout;
  226                 ichwd_write_tco_2(sc, TCO_TMR2, tmr_val16);
  227         }
  228 
  229         sc->timeout = timeout;
  230 
  231         ichwd_verbose_printf(sc->device, "timeout set to %u ticks\n", timeout);
  232 }
  233 
  234 static __inline int
  235 ichwd_clear_noreboot(struct ichwd_softc *sc)
  236 {
  237         uint32_t status;
  238         int rc = 0;
  239 
  240         /* try to clear the NO_REBOOT bit */
  241         if (sc->ich_version <= 5) {
  242                 status = pci_read_config(sc->ich, ICH_GEN_STA, 1);
  243                 status &= ~ICH_GEN_STA_NO_REBOOT;
  244                 pci_write_config(sc->ich, ICH_GEN_STA, status, 1);
  245                 status = pci_read_config(sc->ich, ICH_GEN_STA, 1);
  246                 if (status & ICH_GEN_STA_NO_REBOOT)
  247                         rc = EIO;
  248         } else {
  249                 status = ichwd_read_gcs_4(sc, 0);
  250                 status &= ~ICH_GCS_NO_REBOOT;
  251                 ichwd_write_gcs_4(sc, 0, status);
  252                 status = ichwd_read_gcs_4(sc, 0);
  253                 if (status & ICH_GCS_NO_REBOOT)
  254                         rc = EIO;
  255         }
  256 
  257         if (rc)
  258                 device_printf(sc->device,
  259                     "ICH WDT present but disabled in BIOS or hardware\n");
  260 
  261         return (rc);
  262 }
  263 
  264 /*
  265  * Watchdog event handler.
  266  */
  267 static void
  268 ichwd_event(void *arg, unsigned int cmd, int *error)
  269 {
  270         struct ichwd_softc *sc = arg;
  271         unsigned int timeout;
  272 
  273         /* convert from power-of-two-ns to WDT ticks */
  274         cmd &= WD_INTERVAL;
  275         timeout = ((uint64_t)1 << cmd) / ICHWD_TICK;
  276         if (cmd) {
  277                 if (timeout != sc->timeout) {
  278                         if (!sc->active)
  279                                 ichwd_tmr_enable(sc);
  280                         ichwd_tmr_set(sc, timeout);
  281                 }
  282                 ichwd_tmr_reload(sc);
  283                 *error = 0;
  284         } else {
  285                 if (sc->active)
  286                         ichwd_tmr_disable(sc);
  287         }
  288 }
  289 
  290 static device_t
  291 ichwd_find_ich_lpc_bridge(struct ichwd_device **id_p)
  292 {
  293         struct ichwd_device *id;
  294         device_t ich = NULL;
  295 
  296         /* look for an ICH LPC interface bridge */
  297         for (id = ichwd_devices; id->desc != NULL; ++id)
  298                 if ((ich = pci_find_device(VENDORID_INTEL, id->device)) != NULL)
  299                         break;
  300 
  301         if (ich == NULL)
  302                 return (NULL);
  303 
  304         ichwd_verbose_printf(ich, "found ICH%d or equivalent chipset: %s\n",
  305             id->version, id->desc);
  306 
  307         if (id_p)
  308                 *id_p = id;
  309 
  310         return (ich);
  311 }
  312 
  313 /*
  314  * Look for an ICH LPC interface bridge.  If one is found, register an
  315  * ichwd device.  There can be only one.
  316  */
  317 static void
  318 ichwd_identify(driver_t *driver, device_t parent)
  319 {
  320         struct ichwd_device *id_p;
  321         device_t ich = NULL;
  322         device_t dev;
  323         uint32_t rcba;
  324         int rc;
  325 
  326         ich = ichwd_find_ich_lpc_bridge(&id_p);
  327         if (ich == NULL)
  328                 return;
  329 
  330         /* good, add child to bus */
  331         if ((dev = device_find_child(parent, driver->name, 0)) == NULL)
  332                 dev = BUS_ADD_CHILD(parent, 0, driver->name, 0);
  333 
  334         if (dev == NULL)
  335                 return;
  336 
  337         device_set_desc_copy(dev, id_p->desc);
  338 
  339         if (id_p->version >= 6) {
  340                 /* get RCBA (root complex base address) */
  341                 rcba = pci_read_config(ich, ICH_RCBA, 4);
  342                 rc = bus_set_resource(ich, SYS_RES_MEMORY, 0,
  343                     (rcba & 0xffffc000) + ICH_GCS_OFFSET, ICH_GCS_SIZE);
  344                 if (rc)
  345                         ichwd_verbose_printf(dev,
  346                             "Can not set memory resource for RCBA\n");
  347         }
  348 }
  349 
  350 static int
  351 ichwd_probe(device_t dev)
  352 {
  353 
  354         (void)dev;
  355         return (0);
  356 }
  357 
  358 static int
  359 ichwd_attach(device_t dev)
  360 {
  361         struct ichwd_softc *sc;
  362         struct ichwd_device *id_p;
  363         device_t ich;
  364         unsigned int pmbase = 0;
  365 
  366         sc = device_get_softc(dev);
  367         sc->device = dev;
  368 
  369         ich = ichwd_find_ich_lpc_bridge(&id_p);
  370         if (ich == NULL) {
  371                 device_printf(sc->device, "Can not find ICH device.\n");
  372                 goto fail;
  373         }
  374         sc->ich = ich;
  375         sc->ich_version = id_p->version;
  376 
  377         /* get ACPI base address */
  378         pmbase = pci_read_config(ich, ICH_PMBASE, 2) & ICH_PMBASE_MASK;
  379         if (pmbase == 0) {
  380                 device_printf(dev, "ICH PMBASE register is empty\n");
  381                 goto fail;
  382         }
  383 
  384         /* allocate I/O register space */
  385         sc->smi_rid = 0;
  386         sc->smi_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->smi_rid,
  387             pmbase + SMI_BASE, pmbase + SMI_BASE + SMI_LEN - 1, SMI_LEN,
  388             RF_ACTIVE | RF_SHAREABLE);
  389         if (sc->smi_res == NULL) {
  390                 device_printf(dev, "unable to reserve SMI registers\n");
  391                 goto fail;
  392         }
  393         sc->smi_bst = rman_get_bustag(sc->smi_res);
  394         sc->smi_bsh = rman_get_bushandle(sc->smi_res);
  395 
  396         sc->tco_rid = 1;
  397         sc->tco_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->tco_rid,
  398             pmbase + TCO_BASE, pmbase + TCO_BASE + TCO_LEN - 1, TCO_LEN,
  399             RF_ACTIVE | RF_SHAREABLE);
  400         if (sc->tco_res == NULL) {
  401                 device_printf(dev, "unable to reserve TCO registers\n");
  402                 goto fail;
  403         }
  404         sc->tco_bst = rman_get_bustag(sc->tco_res);
  405         sc->tco_bsh = rman_get_bushandle(sc->tco_res);
  406 
  407         sc->gcs_rid = 0;
  408         if (sc->ich_version >= 6) {
  409                 sc->gcs_res = bus_alloc_resource_any(ich, SYS_RES_MEMORY,
  410                     &sc->gcs_rid, RF_ACTIVE|RF_SHAREABLE);
  411                 if (sc->gcs_res == NULL) {
  412                         device_printf(dev, "unable to reserve GCS registers\n");
  413                         goto fail;
  414                 }
  415                 sc->gcs_bst = rman_get_bustag(sc->gcs_res);
  416                 sc->gcs_bsh = rman_get_bushandle(sc->gcs_res);
  417         } else {
  418                 sc->gcs_res = 0;
  419                 sc->gcs_bst = 0;
  420                 sc->gcs_bsh = 0;
  421         }
  422 
  423         if (ichwd_clear_noreboot(sc) != 0)
  424                 goto fail;
  425 
  426         device_printf(dev, "%s (ICH%d or equivalent)\n",
  427             device_get_desc(dev), sc->ich_version);
  428 
  429         /* reset the watchdog status registers */
  430         ichwd_sts_reset(sc);
  431 
  432         /* make sure the WDT starts out inactive */
  433         ichwd_tmr_disable(sc);
  434 
  435         /* register the watchdog event handler */
  436         sc->ev_tag = EVENTHANDLER_REGISTER(watchdog_list, ichwd_event, sc, 0);
  437 
  438         /* enable watchdog timeout interrupts */
  439         ichwd_intr_enable(sc);
  440 
  441         return (0);
  442  fail:
  443         sc = device_get_softc(dev);
  444         if (sc->tco_res != NULL)
  445                 bus_release_resource(dev, SYS_RES_IOPORT,
  446                     sc->tco_rid, sc->tco_res);
  447         if (sc->smi_res != NULL)
  448                 bus_release_resource(dev, SYS_RES_IOPORT,
  449                     sc->smi_rid, sc->smi_res);
  450         if (sc->gcs_res != NULL)
  451                 bus_release_resource(ich, SYS_RES_MEMORY,
  452                     sc->gcs_rid, sc->gcs_res);
  453 
  454         return (ENXIO);
  455 }
  456 
  457 static int
  458 ichwd_detach(device_t dev)
  459 {
  460         struct ichwd_softc *sc;
  461         device_t ich = NULL;
  462 
  463         sc = device_get_softc(dev);
  464 
  465         /* halt the watchdog timer */
  466         if (sc->active)
  467                 ichwd_tmr_disable(sc);
  468 
  469         /* disable watchdog timeout interrupts */
  470         ichwd_intr_disable(sc);
  471 
  472         /* deregister event handler */
  473         if (sc->ev_tag != NULL)
  474                 EVENTHANDLER_DEREGISTER(watchdog_list, sc->ev_tag);
  475         sc->ev_tag = NULL;
  476 
  477         /* reset the watchdog status registers */
  478         ichwd_sts_reset(sc);
  479 
  480         /* deallocate I/O register space */
  481         bus_release_resource(dev, SYS_RES_IOPORT, sc->tco_rid, sc->tco_res);
  482         bus_release_resource(dev, SYS_RES_IOPORT, sc->smi_rid, sc->smi_res);
  483 
  484         /* deallocate memory resource */
  485         ich = ichwd_find_ich_lpc_bridge(NULL);
  486         if (sc->gcs_res && ich)
  487                 bus_release_resource(ich, SYS_RES_MEMORY, sc->gcs_rid, sc->gcs_res);
  488 
  489         return (0);
  490 }
  491 
  492 static device_method_t ichwd_methods[] = {
  493         DEVMETHOD(device_identify, ichwd_identify),
  494         DEVMETHOD(device_probe, ichwd_probe),
  495         DEVMETHOD(device_attach, ichwd_attach),
  496         DEVMETHOD(device_detach, ichwd_detach),
  497         DEVMETHOD(device_shutdown, ichwd_detach),
  498         {0,0}
  499 };
  500 
  501 static driver_t ichwd_driver = {
  502         "ichwd",
  503         ichwd_methods,
  504         sizeof(struct ichwd_softc),
  505 };
  506 
  507 static int
  508 ichwd_modevent(module_t mode, int type, void *data)
  509 {
  510         int error = 0;
  511 
  512         switch (type) {
  513         case MOD_LOAD:
  514                 printf("ichwd module loaded\n");
  515                 break;
  516         case MOD_UNLOAD:
  517                 printf("ichwd module unloaded\n");
  518                 break;
  519         case MOD_SHUTDOWN:
  520                 printf("ichwd module shutting down\n");
  521                 break;
  522         }
  523         return (error);
  524 }
  525 
  526 DRIVER_MODULE(ichwd, isa, ichwd_driver, ichwd_devclass, ichwd_modevent, NULL);

Cache object: 1e7854aee3ba03cf2184e4e36f3cfea2


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.