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/x86/isa/atrtc.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2008 Poul-Henning Kamp
    5  * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org>
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  * $FreeBSD$
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD$");
   34 
   35 #include "opt_acpi.h"
   36 #include "opt_isa.h"
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/bus.h>
   41 #include <sys/clock.h>
   42 #include <sys/lock.h>
   43 #include <sys/mutex.h>
   44 #include <sys/kdb.h>
   45 #include <sys/kernel.h>
   46 #include <sys/module.h>
   47 #include <sys/proc.h>
   48 #include <sys/rman.h>
   49 #include <sys/timeet.h>
   50 
   51 #include <isa/rtc.h>
   52 #ifdef DEV_ISA
   53 #include <isa/isareg.h>
   54 #include <isa/isavar.h>
   55 #endif
   56 #include <machine/intr_machdep.h>
   57 #include "clock_if.h"
   58 #ifdef DEV_ACPI
   59 #include <contrib/dev/acpica/include/acpi.h>
   60 #include <contrib/dev/acpica/include/accommon.h>
   61 #include <dev/acpica/acpivar.h>
   62 #include <machine/md_var.h>
   63 #endif
   64 
   65 /*
   66  * atrtc_lock protects low-level access to individual hardware registers.
   67  * atrtc_time_lock protects the entire sequence of accessing multiple registers
   68  * to read or write the date and time.
   69  */
   70 static struct mtx atrtc_lock;
   71 MTX_SYSINIT(atrtc_lock_init, &atrtc_lock, "atrtc", MTX_SPIN);
   72 
   73 /* Force RTC enabled/disabled. */
   74 static int atrtc_enabled = -1;
   75 TUNABLE_INT("hw.atrtc.enabled", &atrtc_enabled);
   76 
   77 struct mtx atrtc_time_lock;
   78 MTX_SYSINIT(atrtc_time_lock_init, &atrtc_time_lock, "atrtc_time", MTX_DEF);
   79 
   80 int     atrtcclock_disable = 0;
   81 
   82 static  int     rtc_reg = -1;
   83 static  u_char  rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
   84 static  u_char  rtc_statusb = RTCSB_24HR;
   85 
   86 #ifdef DEV_ACPI
   87 #define _COMPONENT      ACPI_TIMER
   88 ACPI_MODULE_NAME("ATRTC")
   89 #endif
   90 
   91 /*
   92  * RTC support routines
   93  */
   94 
   95 static inline u_char
   96 rtcin_locked(int reg)
   97 {
   98 
   99         if (rtc_reg != reg) {
  100                 inb(0x84);
  101                 outb(IO_RTC, reg);
  102                 rtc_reg = reg;
  103                 inb(0x84);
  104         }
  105         return (inb(IO_RTC + 1));
  106 }
  107 
  108 static inline void
  109 rtcout_locked(int reg, u_char val)
  110 {
  111 
  112         if (rtc_reg != reg) {
  113                 inb(0x84);
  114                 outb(IO_RTC, reg);
  115                 rtc_reg = reg;
  116                 inb(0x84);
  117         }
  118         outb(IO_RTC + 1, val);
  119         inb(0x84);
  120 }
  121 
  122 int
  123 rtcin(int reg)
  124 {
  125         u_char val;
  126 
  127         mtx_lock_spin(&atrtc_lock);
  128         val = rtcin_locked(reg);
  129         mtx_unlock_spin(&atrtc_lock);
  130         return (val);
  131 }
  132 
  133 void
  134 writertc(int reg, u_char val)
  135 {
  136 
  137         mtx_lock_spin(&atrtc_lock);
  138         rtcout_locked(reg, val);
  139         mtx_unlock_spin(&atrtc_lock);
  140 }
  141 
  142 static void
  143 atrtc_start(void)
  144 {
  145 
  146         mtx_lock_spin(&atrtc_lock);
  147         rtcout_locked(RTC_STATUSA, rtc_statusa);
  148         rtcout_locked(RTC_STATUSB, RTCSB_24HR);
  149         mtx_unlock_spin(&atrtc_lock);
  150 }
  151 
  152 static void
  153 atrtc_rate(unsigned rate)
  154 {
  155 
  156         rtc_statusa = RTCSA_DIVIDER | rate;
  157         writertc(RTC_STATUSA, rtc_statusa);
  158 }
  159 
  160 static void
  161 atrtc_enable_intr(void)
  162 {
  163 
  164         rtc_statusb |= RTCSB_PINTR;
  165         mtx_lock_spin(&atrtc_lock);
  166         rtcout_locked(RTC_STATUSB, rtc_statusb);
  167         rtcin_locked(RTC_INTR);
  168         mtx_unlock_spin(&atrtc_lock);
  169 }
  170 
  171 static void
  172 atrtc_disable_intr(void)
  173 {
  174 
  175         rtc_statusb &= ~RTCSB_PINTR;
  176         mtx_lock_spin(&atrtc_lock);
  177         rtcout_locked(RTC_STATUSB, rtc_statusb);
  178         rtcin_locked(RTC_INTR);
  179         mtx_unlock_spin(&atrtc_lock);
  180 }
  181 
  182 void
  183 atrtc_restore(void)
  184 {
  185 
  186         /* Restore all of the RTC's "status" (actually, control) registers. */
  187         mtx_lock_spin(&atrtc_lock);
  188         rtcin_locked(RTC_STATUSA);      /* dummy to get rtc_reg set */
  189         rtcout_locked(RTC_STATUSB, RTCSB_24HR);
  190         rtcout_locked(RTC_STATUSA, rtc_statusa);
  191         rtcout_locked(RTC_STATUSB, rtc_statusb);
  192         rtcin_locked(RTC_INTR);
  193         mtx_unlock_spin(&atrtc_lock);
  194 }
  195 
  196 /**********************************************************************
  197  * RTC driver for subr_rtc
  198  */
  199 
  200 struct atrtc_softc {
  201         int port_rid, intr_rid;
  202         struct resource *port_res;
  203         struct resource *intr_res;
  204         void *intr_handler;
  205         struct eventtimer et;
  206 #ifdef DEV_ACPI
  207         ACPI_HANDLE acpi_handle;
  208 #endif
  209 };
  210 
  211 static int
  212 rtc_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
  213 {
  214 
  215         atrtc_rate(max(fls(period + (period >> 1)) - 17, 1));
  216         atrtc_enable_intr();
  217         return (0);
  218 }
  219 
  220 static int
  221 rtc_stop(struct eventtimer *et)
  222 {
  223 
  224         atrtc_disable_intr();
  225         return (0);
  226 }
  227 
  228 /*
  229  * This routine receives statistical clock interrupts from the RTC.
  230  * As explained above, these occur at 128 interrupts per second.
  231  * When profiling, we receive interrupts at a rate of 1024 Hz.
  232  *
  233  * This does not actually add as much overhead as it sounds, because
  234  * when the statistical clock is active, the hardclock driver no longer
  235  * needs to keep (inaccurate) statistics on its own.  This decouples
  236  * statistics gathering from scheduling interrupts.
  237  *
  238  * The RTC chip requires that we read status register C (RTC_INTR)
  239  * to acknowledge an interrupt, before it will generate the next one.
  240  * Under high interrupt load, rtcintr() can be indefinitely delayed and
  241  * the clock can tick immediately after the read from RTC_INTR.  In this
  242  * case, the mc146818A interrupt signal will not drop for long enough
  243  * to register with the 8259 PIC.  If an interrupt is missed, the stat
  244  * clock will halt, considerably degrading system performance.  This is
  245  * why we use 'while' rather than a more straightforward 'if' below.
  246  * Stat clock ticks can still be lost, causing minor loss of accuracy
  247  * in the statistics, but the stat clock will no longer stop.
  248  */
  249 static int
  250 rtc_intr(void *arg)
  251 {
  252         struct atrtc_softc *sc = (struct atrtc_softc *)arg;
  253         int flag = 0;
  254 
  255         while (rtcin(RTC_INTR) & RTCIR_PERIOD) {
  256                 flag = 1;
  257                 if (sc->et.et_active)
  258                         sc->et.et_event_cb(&sc->et, sc->et.et_arg);
  259         }
  260         return(flag ? FILTER_HANDLED : FILTER_STRAY);
  261 }
  262 
  263 #ifdef DEV_ACPI
  264 /*
  265  *  ACPI RTC CMOS address space handler
  266  */
  267 #define ATRTC_LAST_REG  0x40
  268 
  269 static void
  270 rtcin_region(int reg, void *buf, int len)
  271 {
  272         u_char *ptr = buf;
  273 
  274         /* Drop lock after each IO as intr and settime have greater priority */
  275         while (len-- > 0)
  276                 *ptr++ = rtcin(reg++) & 0xff;
  277 }
  278 
  279 static void
  280 rtcout_region(int reg, const void *buf, int len)
  281 {
  282         const u_char *ptr = buf;
  283 
  284         while (len-- > 0)
  285                 writertc(reg++, *ptr++);
  286 }
  287 
  288 static bool
  289 atrtc_check_cmos_access(bool is_read, ACPI_PHYSICAL_ADDRESS addr, UINT32 len)
  290 {
  291 
  292         /* Block address space wrapping on out-of-bound access */
  293         if (addr >= ATRTC_LAST_REG || addr + len > ATRTC_LAST_REG)
  294                 return (false);
  295 
  296         if (is_read) {
  297                 /* Reading 0x0C will muck with interrupts */
  298                 if (addr <= RTC_INTR && addr + len > RTC_INTR)
  299                         return (false);
  300         } else {
  301                 /*
  302                  * Allow single-byte writes to alarm registers and
  303                  * multi-byte writes to addr >= 0x30, else deny.
  304                  */
  305                 if (!((len == 1 && (addr == RTC_SECALRM ||
  306                                     addr == RTC_MINALRM ||
  307                                     addr == RTC_HRSALRM)) ||
  308                       addr >= 0x30))
  309                         return (false);
  310         }
  311         return (true);
  312 }
  313 
  314 static ACPI_STATUS
  315 atrtc_acpi_cmos_handler(UINT32 func, ACPI_PHYSICAL_ADDRESS addr,
  316     UINT32 bitwidth, UINT64 *value, void *context, void *region_context)
  317 {
  318         device_t dev = context;
  319         UINT32 bytewidth = howmany(bitwidth, 8);
  320         bool is_read = func == ACPI_READ;
  321 
  322         /* ACPICA is very verbose on CMOS handler failures, so we, too */
  323 #define CMOS_HANDLER_ERR(fmt, ...) \
  324         device_printf(dev, "ACPI [SystemCMOS] handler: " fmt, ##__VA_ARGS__)
  325 
  326         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  327 
  328         if (value == NULL) {
  329                 CMOS_HANDLER_ERR("NULL parameter\n");
  330                 return (AE_BAD_PARAMETER);
  331         }
  332         if (bitwidth == 0 || (bitwidth & 0x07) != 0) {
  333                 CMOS_HANDLER_ERR("Invalid bitwidth: %u\n", bitwidth);
  334                 return (AE_BAD_PARAMETER);
  335         }
  336         if (!atrtc_check_cmos_access(is_read, addr, bytewidth)) {
  337                 CMOS_HANDLER_ERR("%s access rejected: addr=%#04jx, len=%u\n",
  338                     is_read ? "Read" : "Write", (uintmax_t)addr, bytewidth);
  339                 return (AE_BAD_PARAMETER);
  340         }
  341 
  342         switch (func) {
  343         case ACPI_READ:
  344                 rtcin_region(addr, value, bytewidth);
  345                 break;
  346         case ACPI_WRITE:
  347                 rtcout_region(addr, value, bytewidth);
  348                 break;
  349         default:
  350                 CMOS_HANDLER_ERR("Invalid function: %u\n", func);
  351                 return (AE_BAD_PARAMETER);
  352         }
  353 
  354         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
  355             "ACPI RTC CMOS %s access: addr=%#04x, len=%u, val=%*D\n",
  356             is_read ? "read" : "write", (unsigned)addr, bytewidth,
  357             bytewidth, value, " ");
  358 
  359         return (AE_OK);
  360 }
  361 
  362 static int
  363 atrtc_reg_acpi_cmos_handler(device_t dev)
  364 {
  365         struct atrtc_softc *sc = device_get_softc(dev);
  366 
  367         ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
  368 
  369         /* Don't handle address space events if driver is disabled. */
  370         if (acpi_disabled("atrtc"))
  371                 return (ENXIO);
  372 
  373         sc->acpi_handle = acpi_get_handle(dev);
  374         if (sc->acpi_handle == NULL ||
  375             ACPI_FAILURE(AcpiInstallAddressSpaceHandler(sc->acpi_handle,
  376               ACPI_ADR_SPACE_CMOS, atrtc_acpi_cmos_handler, NULL, dev))) {
  377                 sc->acpi_handle = NULL;
  378                 device_printf(dev,
  379                     "Can't register ACPI CMOS address space handler\n");
  380                 return (ENXIO);
  381         }
  382 
  383         return (0);
  384 }
  385 
  386 static int
  387 atrtc_unreg_acpi_cmos_handler(device_t dev)
  388 {
  389         struct atrtc_softc *sc = device_get_softc(dev);
  390 
  391         ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
  392 
  393         if (sc->acpi_handle != NULL)
  394                 AcpiRemoveAddressSpaceHandler(sc->acpi_handle,
  395                     ACPI_ADR_SPACE_CMOS, atrtc_acpi_cmos_handler);
  396 
  397         return (0);
  398 }
  399 #endif  /* DEV_ACPI */
  400 
  401 /*
  402  * Attach to the ISA PnP descriptors for the timer and realtime clock.
  403  */
  404 static struct isa_pnp_id atrtc_ids[] = {
  405         { 0x000bd041 /* PNP0B00 */, "AT realtime clock" },
  406         { 0 }
  407 };
  408 
  409 static bool
  410 atrtc_acpi_disabled(void)
  411 {
  412 #ifdef DEV_ACPI
  413         uint16_t flags;
  414 
  415         if (!acpi_get_fadt_bootflags(&flags))
  416                 return (false);
  417         return ((flags & ACPI_FADT_NO_CMOS_RTC) != 0);
  418 #else
  419         return (false);
  420 #endif
  421 }
  422 
  423 static int
  424 atrtc_probe(device_t dev)
  425 {
  426         int result;
  427 
  428         if ((atrtc_enabled == -1 && atrtc_acpi_disabled()) ||
  429             (atrtc_enabled == 0))
  430                 return (ENXIO);
  431 
  432         result = ISA_PNP_PROBE(device_get_parent(dev), dev, atrtc_ids);
  433         /* ENOENT means no PnP-ID, device is hinted. */
  434         if (result == ENOENT) {
  435                 device_set_desc(dev, "AT realtime clock");
  436                 return (BUS_PROBE_LOW_PRIORITY);
  437         }
  438         return (result);
  439 }
  440 
  441 static int
  442 atrtc_attach(device_t dev)
  443 {
  444         struct atrtc_softc *sc;
  445         rman_res_t s;
  446         int i;
  447 
  448         sc = device_get_softc(dev);
  449         sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid,
  450             IO_RTC, IO_RTC + 1, 2, RF_ACTIVE);
  451         if (sc->port_res == NULL)
  452                 device_printf(dev, "Warning: Couldn't map I/O.\n");
  453         atrtc_start();
  454         clock_register(dev, 1000000);
  455         bzero(&sc->et, sizeof(struct eventtimer));
  456         if (!atrtcclock_disable &&
  457             (resource_int_value(device_get_name(dev), device_get_unit(dev),
  458              "clock", &i) != 0 || i != 0)) {
  459                 sc->intr_rid = 0;
  460                 while (bus_get_resource(dev, SYS_RES_IRQ, sc->intr_rid,
  461                     &s, NULL) == 0 && s != 8)
  462                         sc->intr_rid++;
  463                 sc->intr_res = bus_alloc_resource(dev, SYS_RES_IRQ,
  464                     &sc->intr_rid, 8, 8, 1, RF_ACTIVE);
  465                 if (sc->intr_res == NULL) {
  466                         device_printf(dev, "Can't map interrupt.\n");
  467                         return (0);
  468                 } else if ((bus_setup_intr(dev, sc->intr_res, INTR_TYPE_CLK,
  469                     rtc_intr, NULL, sc, &sc->intr_handler))) {
  470                         device_printf(dev, "Can't setup interrupt.\n");
  471                         return (0);
  472                 } else { 
  473                         /* Bind IRQ to BSP to avoid live migration. */
  474                         bus_bind_intr(dev, sc->intr_res, 0);
  475                 }
  476                 sc->et.et_name = "RTC";
  477                 sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_POW2DIV;
  478                 sc->et.et_quality = 0;
  479                 sc->et.et_frequency = 32768;
  480                 sc->et.et_min_period = 0x00080000;
  481                 sc->et.et_max_period = 0x80000000;
  482                 sc->et.et_start = rtc_start;
  483                 sc->et.et_stop = rtc_stop;
  484                 sc->et.et_priv = dev;
  485                 et_register(&sc->et);
  486         }
  487         return(0);
  488 }
  489 
  490 static int
  491 atrtc_isa_attach(device_t dev)
  492 {
  493 
  494         return (atrtc_attach(dev));
  495 }
  496 
  497 #ifdef DEV_ACPI
  498 static int
  499 atrtc_acpi_attach(device_t dev)
  500 {
  501         int ret;
  502 
  503         ret = atrtc_attach(dev);
  504         if (ret)
  505                 return (ret);
  506 
  507         (void)atrtc_reg_acpi_cmos_handler(dev);
  508 
  509         return (0);
  510 }
  511 
  512 static int
  513 atrtc_acpi_detach(device_t dev)
  514 {
  515 
  516         (void)atrtc_unreg_acpi_cmos_handler(dev);
  517         return (0);
  518 }
  519 #endif  /* DEV_ACPI */
  520 
  521 static int
  522 atrtc_resume(device_t dev)
  523 {
  524 
  525         atrtc_restore();
  526         return(0);
  527 }
  528 
  529 static int
  530 atrtc_settime(device_t dev __unused, struct timespec *ts)
  531 {
  532         struct bcd_clocktime bct;
  533 
  534         clock_ts_to_bcd(ts, &bct, false);
  535         clock_dbgprint_bcd(dev, CLOCK_DBG_WRITE, &bct);
  536 
  537         mtx_lock(&atrtc_time_lock);
  538         mtx_lock_spin(&atrtc_lock);
  539 
  540         /* Disable RTC updates and interrupts.  */
  541         rtcout_locked(RTC_STATUSB, RTCSB_HALT | RTCSB_24HR);
  542 
  543         /* Write all the time registers. */
  544         rtcout_locked(RTC_SEC,   bct.sec);
  545         rtcout_locked(RTC_MIN,   bct.min);
  546         rtcout_locked(RTC_HRS,   bct.hour);
  547         rtcout_locked(RTC_WDAY,  bct.dow + 1);
  548         rtcout_locked(RTC_DAY,   bct.day);
  549         rtcout_locked(RTC_MONTH, bct.mon);
  550         rtcout_locked(RTC_YEAR,  bct.year & 0xff);
  551 #ifdef USE_RTC_CENTURY
  552         rtcout_locked(RTC_CENTURY, bct.year >> 8);
  553 #endif
  554 
  555         /*
  556          * Re-enable RTC updates and interrupts.
  557          */
  558         rtcout_locked(RTC_STATUSB, rtc_statusb);
  559         rtcin_locked(RTC_INTR);
  560 
  561         mtx_unlock_spin(&atrtc_lock);
  562         mtx_unlock(&atrtc_time_lock);
  563 
  564         return (0);
  565 }
  566 
  567 static int
  568 atrtc_gettime(device_t dev, struct timespec *ts)
  569 {
  570         struct bcd_clocktime bct;
  571 
  572         /* Look if we have a RTC present and the time is valid */
  573         if (!(rtcin(RTC_STATUSD) & RTCSD_PWR)) {
  574                 device_printf(dev, "WARNING: Battery failure indication\n");
  575                 return (EINVAL);
  576         }
  577 
  578         /*
  579          * wait for time update to complete
  580          * If RTCSA_TUP is zero, we have at least 244us before next update.
  581          * This is fast enough on most hardware, but a refinement would be
  582          * to make sure that no more than 240us pass after we start reading,
  583          * and try again if so.
  584          */
  585         mtx_lock(&atrtc_time_lock);
  586         while (rtcin(RTC_STATUSA) & RTCSA_TUP)
  587                 continue;
  588         mtx_lock_spin(&atrtc_lock);
  589         bct.sec  = rtcin_locked(RTC_SEC);
  590         bct.min  = rtcin_locked(RTC_MIN);
  591         bct.hour = rtcin_locked(RTC_HRS);
  592         bct.day  = rtcin_locked(RTC_DAY);
  593         bct.mon  = rtcin_locked(RTC_MONTH);
  594         bct.year = rtcin_locked(RTC_YEAR);
  595 #ifdef USE_RTC_CENTURY
  596         bct.year |= rtcin_locked(RTC_CENTURY) << 8;
  597 #endif
  598         mtx_unlock_spin(&atrtc_lock);
  599         mtx_unlock(&atrtc_time_lock);
  600         /* dow is unused in timespec conversion and we have no nsec info. */
  601         bct.dow  = 0;
  602         bct.nsec = 0;
  603         clock_dbgprint_bcd(dev, CLOCK_DBG_READ, &bct);
  604         return (clock_bcd_to_ts(&bct, ts, false));
  605 }
  606 
  607 static device_method_t atrtc_isa_methods[] = {
  608         /* Device interface */
  609         DEVMETHOD(device_probe,         atrtc_probe),
  610         DEVMETHOD(device_attach,        atrtc_isa_attach),
  611         DEVMETHOD(device_detach,        bus_generic_detach),
  612         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  613         DEVMETHOD(device_suspend,       bus_generic_suspend),
  614                 /* XXX stop statclock? */
  615         DEVMETHOD(device_resume,        atrtc_resume),
  616 
  617         /* clock interface */
  618         DEVMETHOD(clock_gettime,        atrtc_gettime),
  619         DEVMETHOD(clock_settime,        atrtc_settime),
  620 
  621         { 0, 0 }
  622 };
  623 
  624 static driver_t atrtc_isa_driver = {
  625         "atrtc",
  626         atrtc_isa_methods,
  627         sizeof(struct atrtc_softc),
  628 };
  629 
  630 #ifdef DEV_ACPI
  631 static device_method_t atrtc_acpi_methods[] = {
  632         /* Device interface */
  633         DEVMETHOD(device_probe,         atrtc_probe),
  634         DEVMETHOD(device_attach,        atrtc_acpi_attach),
  635         DEVMETHOD(device_detach,        atrtc_acpi_detach),
  636                 /* XXX stop statclock? */
  637         DEVMETHOD(device_resume,        atrtc_resume),
  638 
  639         /* clock interface */
  640         DEVMETHOD(clock_gettime,        atrtc_gettime),
  641         DEVMETHOD(clock_settime,        atrtc_settime),
  642 
  643         { 0, 0 }
  644 };
  645 
  646 static driver_t atrtc_acpi_driver = {
  647         "atrtc",
  648         atrtc_acpi_methods,
  649         sizeof(struct atrtc_softc),
  650 };
  651 #endif  /* DEV_ACPI */
  652 
  653 static devclass_t atrtc_devclass;
  654 
  655 DRIVER_MODULE(atrtc, isa, atrtc_isa_driver, atrtc_devclass, 0, 0);
  656 #ifdef DEV_ACPI
  657 DRIVER_MODULE(atrtc, acpi, atrtc_acpi_driver, atrtc_devclass, 0, 0);
  658 #endif
  659 ISA_PNP_INFO(atrtc_ids);

Cache object: fa7384448bef3eda9fb7cce56627d5a5


[ 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.