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_century = 0;
   83 static  int     rtc_reg = -1;
   84 static  u_char  rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
   85 static  u_char  rtc_statusb = RTCSB_24HR;
   86 
   87 #ifdef DEV_ACPI
   88 #define _COMPONENT      ACPI_TIMER
   89 ACPI_MODULE_NAME("ATRTC")
   90 #endif
   91 
   92 /*
   93  * RTC support routines
   94  */
   95 
   96 static inline u_char
   97 rtcin_locked(int reg)
   98 {
   99 
  100         if (rtc_reg != reg) {
  101                 inb(0x84);
  102                 outb(IO_RTC, reg);
  103                 rtc_reg = reg;
  104                 inb(0x84);
  105         }
  106         return (inb(IO_RTC + 1));
  107 }
  108 
  109 static inline void
  110 rtcout_locked(int reg, u_char val)
  111 {
  112 
  113         if (rtc_reg != reg) {
  114                 inb(0x84);
  115                 outb(IO_RTC, reg);
  116                 rtc_reg = reg;
  117                 inb(0x84);
  118         }
  119         outb(IO_RTC + 1, val);
  120         inb(0x84);
  121 }
  122 
  123 int
  124 rtcin(int reg)
  125 {
  126         u_char val;
  127 
  128         mtx_lock_spin(&atrtc_lock);
  129         val = rtcin_locked(reg);
  130         mtx_unlock_spin(&atrtc_lock);
  131         return (val);
  132 }
  133 
  134 void
  135 writertc(int reg, u_char val)
  136 {
  137 
  138         mtx_lock_spin(&atrtc_lock);
  139         rtcout_locked(reg, val);
  140         mtx_unlock_spin(&atrtc_lock);
  141 }
  142 
  143 static void
  144 atrtc_start(void)
  145 {
  146 
  147         mtx_lock_spin(&atrtc_lock);
  148         rtcout_locked(RTC_STATUSA, rtc_statusa);
  149         rtcout_locked(RTC_STATUSB, RTCSB_24HR);
  150         mtx_unlock_spin(&atrtc_lock);
  151 }
  152 
  153 static void
  154 atrtc_rate(unsigned rate)
  155 {
  156 
  157         rtc_statusa = RTCSA_DIVIDER | rate;
  158         writertc(RTC_STATUSA, rtc_statusa);
  159 }
  160 
  161 static void
  162 atrtc_enable_intr(void)
  163 {
  164 
  165         rtc_statusb |= RTCSB_PINTR;
  166         mtx_lock_spin(&atrtc_lock);
  167         rtcout_locked(RTC_STATUSB, rtc_statusb);
  168         rtcin_locked(RTC_INTR);
  169         mtx_unlock_spin(&atrtc_lock);
  170 }
  171 
  172 static void
  173 atrtc_disable_intr(void)
  174 {
  175 
  176         rtc_statusb &= ~RTCSB_PINTR;
  177         mtx_lock_spin(&atrtc_lock);
  178         rtcout_locked(RTC_STATUSB, rtc_statusb);
  179         rtcin_locked(RTC_INTR);
  180         mtx_unlock_spin(&atrtc_lock);
  181 }
  182 
  183 void
  184 atrtc_restore(void)
  185 {
  186 
  187         /* Restore all of the RTC's "status" (actually, control) registers. */
  188         mtx_lock_spin(&atrtc_lock);
  189         rtcin_locked(RTC_STATUSA);      /* dummy to get rtc_reg set */
  190         rtcout_locked(RTC_STATUSB, RTCSB_24HR);
  191         rtcout_locked(RTC_STATUSA, rtc_statusa);
  192         rtcout_locked(RTC_STATUSB, rtc_statusb);
  193         rtcin_locked(RTC_INTR);
  194         mtx_unlock_spin(&atrtc_lock);
  195 }
  196 
  197 /**********************************************************************
  198  * RTC driver for subr_rtc
  199  */
  200 
  201 struct atrtc_softc {
  202         int port_rid, intr_rid;
  203         struct resource *port_res;
  204         struct resource *intr_res;
  205         void *intr_handler;
  206         struct eventtimer et;
  207 #ifdef DEV_ACPI
  208         ACPI_HANDLE acpi_handle;
  209 #endif
  210 };
  211 
  212 static int
  213 rtc_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
  214 {
  215 
  216         atrtc_rate(max(fls(period + (period >> 1)) - 17, 1));
  217         atrtc_enable_intr();
  218         return (0);
  219 }
  220 
  221 static int
  222 rtc_stop(struct eventtimer *et)
  223 {
  224 
  225         atrtc_disable_intr();
  226         return (0);
  227 }
  228 
  229 /*
  230  * This routine receives statistical clock interrupts from the RTC.
  231  * As explained above, these occur at 128 interrupts per second.
  232  * When profiling, we receive interrupts at a rate of 1024 Hz.
  233  *
  234  * This does not actually add as much overhead as it sounds, because
  235  * when the statistical clock is active, the hardclock driver no longer
  236  * needs to keep (inaccurate) statistics on its own.  This decouples
  237  * statistics gathering from scheduling interrupts.
  238  *
  239  * The RTC chip requires that we read status register C (RTC_INTR)
  240  * to acknowledge an interrupt, before it will generate the next one.
  241  * Under high interrupt load, rtcintr() can be indefinitely delayed and
  242  * the clock can tick immediately after the read from RTC_INTR.  In this
  243  * case, the mc146818A interrupt signal will not drop for long enough
  244  * to register with the 8259 PIC.  If an interrupt is missed, the stat
  245  * clock will halt, considerably degrading system performance.  This is
  246  * why we use 'while' rather than a more straightforward 'if' below.
  247  * Stat clock ticks can still be lost, causing minor loss of accuracy
  248  * in the statistics, but the stat clock will no longer stop.
  249  */
  250 static int
  251 rtc_intr(void *arg)
  252 {
  253         struct atrtc_softc *sc = (struct atrtc_softc *)arg;
  254         int flag = 0;
  255 
  256         while (rtcin(RTC_INTR) & RTCIR_PERIOD) {
  257                 flag = 1;
  258                 if (sc->et.et_active)
  259                         sc->et.et_event_cb(&sc->et, sc->et.et_arg);
  260         }
  261         return(flag ? FILTER_HANDLED : FILTER_STRAY);
  262 }
  263 
  264 #ifdef DEV_ACPI
  265 /*
  266  *  ACPI RTC CMOS address space handler
  267  */
  268 #define ATRTC_LAST_REG  0x40
  269 
  270 static void
  271 rtcin_region(int reg, void *buf, int len)
  272 {
  273         u_char *ptr = buf;
  274 
  275         /* Drop lock after each IO as intr and settime have greater priority */
  276         while (len-- > 0)
  277                 *ptr++ = rtcin(reg++) & 0xff;
  278 }
  279 
  280 static void
  281 rtcout_region(int reg, const void *buf, int len)
  282 {
  283         const u_char *ptr = buf;
  284 
  285         while (len-- > 0)
  286                 writertc(reg++, *ptr++);
  287 }
  288 
  289 static bool
  290 atrtc_check_cmos_access(bool is_read, ACPI_PHYSICAL_ADDRESS addr, UINT32 len)
  291 {
  292 
  293         /* Block address space wrapping on out-of-bound access */
  294         if (addr >= ATRTC_LAST_REG || addr + len > ATRTC_LAST_REG)
  295                 return (false);
  296 
  297         if (is_read) {
  298                 /* Reading 0x0C will muck with interrupts */
  299                 if (addr <= RTC_INTR && addr + len > RTC_INTR)
  300                         return (false);
  301         } else {
  302                 /*
  303                  * Allow single-byte writes to alarm registers and
  304                  * multi-byte writes to addr >= 0x30, else deny.
  305                  */
  306                 if (!((len == 1 && (addr == RTC_SECALRM ||
  307                                     addr == RTC_MINALRM ||
  308                                     addr == RTC_HRSALRM)) ||
  309                       addr >= 0x30))
  310                         return (false);
  311         }
  312         return (true);
  313 }
  314 
  315 static ACPI_STATUS
  316 atrtc_acpi_cmos_handler(UINT32 func, ACPI_PHYSICAL_ADDRESS addr,
  317     UINT32 bitwidth, UINT64 *value, void *context, void *region_context)
  318 {
  319         device_t dev = context;
  320         UINT32 bytewidth = howmany(bitwidth, 8);
  321         bool is_read = func == ACPI_READ;
  322 
  323         /* ACPICA is very verbose on CMOS handler failures, so we, too */
  324 #define CMOS_HANDLER_ERR(fmt, ...) \
  325         device_printf(dev, "ACPI [SystemCMOS] handler: " fmt, ##__VA_ARGS__)
  326 
  327         ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  328 
  329         if (value == NULL) {
  330                 CMOS_HANDLER_ERR("NULL parameter\n");
  331                 return (AE_BAD_PARAMETER);
  332         }
  333         if (bitwidth == 0 || (bitwidth & 0x07) != 0) {
  334                 CMOS_HANDLER_ERR("Invalid bitwidth: %u\n", bitwidth);
  335                 return (AE_BAD_PARAMETER);
  336         }
  337         if (!atrtc_check_cmos_access(is_read, addr, bytewidth)) {
  338                 CMOS_HANDLER_ERR("%s access rejected: addr=%#04jx, len=%u\n",
  339                     is_read ? "Read" : "Write", (uintmax_t)addr, bytewidth);
  340                 return (AE_BAD_PARAMETER);
  341         }
  342 
  343         switch (func) {
  344         case ACPI_READ:
  345                 rtcin_region(addr, value, bytewidth);
  346                 break;
  347         case ACPI_WRITE:
  348                 rtcout_region(addr, value, bytewidth);
  349                 break;
  350         default:
  351                 CMOS_HANDLER_ERR("Invalid function: %u\n", func);
  352                 return (AE_BAD_PARAMETER);
  353         }
  354 
  355         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
  356             "ACPI RTC CMOS %s access: addr=%#04x, len=%u, val=%*D\n",
  357             is_read ? "read" : "write", (unsigned)addr, bytewidth,
  358             bytewidth, value, " ");
  359 
  360         return (AE_OK);
  361 }
  362 
  363 static int
  364 atrtc_reg_acpi_cmos_handler(device_t dev)
  365 {
  366         struct atrtc_softc *sc = device_get_softc(dev);
  367 
  368         ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
  369 
  370         /* Don't handle address space events if driver is disabled. */
  371         if (acpi_disabled("atrtc"))
  372                 return (ENXIO);
  373 
  374         if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &sc->acpi_handle))) {
  375                 return (ENXIO);
  376         }
  377 
  378         if (sc->acpi_handle == NULL ||
  379             ACPI_FAILURE(AcpiInstallAddressSpaceHandler(sc->acpi_handle,
  380               ACPI_ADR_SPACE_CMOS, atrtc_acpi_cmos_handler, NULL, dev))) {
  381                 sc->acpi_handle = NULL;
  382                 device_printf(dev,
  383                     "Can't register ACPI CMOS address space handler\n");
  384                 return (ENXIO);
  385         }
  386 
  387         return (0);
  388 }
  389 
  390 static int
  391 atrtc_unreg_acpi_cmos_handler(device_t dev)
  392 {
  393         struct atrtc_softc *sc = device_get_softc(dev);
  394 
  395         ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
  396 
  397         if (sc->acpi_handle != NULL)
  398                 AcpiRemoveAddressSpaceHandler(sc->acpi_handle,
  399                     ACPI_ADR_SPACE_CMOS, atrtc_acpi_cmos_handler);
  400 
  401         return (0);
  402 }
  403 #endif  /* DEV_ACPI */
  404 
  405 /*
  406  * Attach to the ISA PnP descriptors for the timer and realtime clock.
  407  */
  408 static struct isa_pnp_id atrtc_ids[] = {
  409         { 0x000bd041 /* PNP0B00 */, "AT realtime clock" },
  410         { 0 }
  411 };
  412 
  413 static bool
  414 atrtc_acpi_disabled(void)
  415 {
  416 #ifdef DEV_ACPI
  417         uint16_t flags;
  418 
  419         if (!acpi_get_fadt_bootflags(&flags))
  420                 return (false);
  421         return ((flags & ACPI_FADT_NO_CMOS_RTC) != 0);
  422 #else
  423         return (false);
  424 #endif
  425 }
  426 
  427 static int
  428 rtc_acpi_century_get(void)
  429 {
  430 #ifdef DEV_ACPI
  431         ACPI_TABLE_FADT *fadt;
  432         vm_paddr_t physaddr;
  433         int century;
  434 
  435         physaddr = acpi_find_table(ACPI_SIG_FADT);
  436         if (physaddr == 0)
  437                 return (0);
  438 
  439         fadt = acpi_map_table(physaddr, ACPI_SIG_FADT);
  440         if (fadt == NULL)
  441                 return (0);
  442 
  443         century = fadt->Century;
  444         acpi_unmap_table(fadt);
  445 
  446         return (century);
  447 #else
  448         return (0);
  449 #endif
  450 }
  451 
  452 static int
  453 atrtc_probe(device_t dev)
  454 {
  455         int result;
  456 
  457         if ((atrtc_enabled == -1 && atrtc_acpi_disabled()) ||
  458             (atrtc_enabled == 0))
  459                 return (ENXIO);
  460 
  461         result = ISA_PNP_PROBE(device_get_parent(dev), dev, atrtc_ids);
  462         /* ENOENT means no PnP-ID, device is hinted. */
  463         if (result == ENOENT) {
  464                 device_set_desc(dev, "AT realtime clock");
  465                 return (BUS_PROBE_LOW_PRIORITY);
  466         }
  467         rtc_century = rtc_acpi_century_get();
  468         return (result);
  469 }
  470 
  471 static int
  472 atrtc_attach(device_t dev)
  473 {
  474         struct atrtc_softc *sc;
  475         rman_res_t s;
  476         int i;
  477 
  478         sc = device_get_softc(dev);
  479         sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid,
  480             IO_RTC, IO_RTC + 1, 2, RF_ACTIVE);
  481         if (sc->port_res == NULL)
  482                 device_printf(dev, "Warning: Couldn't map I/O.\n");
  483         atrtc_start();
  484         clock_register(dev, 1000000);
  485         bzero(&sc->et, sizeof(struct eventtimer));
  486         if (!atrtcclock_disable &&
  487             (resource_int_value(device_get_name(dev), device_get_unit(dev),
  488              "clock", &i) != 0 || i != 0)) {
  489                 sc->intr_rid = 0;
  490                 while (bus_get_resource(dev, SYS_RES_IRQ, sc->intr_rid,
  491                     &s, NULL) == 0 && s != 8)
  492                         sc->intr_rid++;
  493                 sc->intr_res = bus_alloc_resource(dev, SYS_RES_IRQ,
  494                     &sc->intr_rid, 8, 8, 1, RF_ACTIVE);
  495                 if (sc->intr_res == NULL) {
  496                         device_printf(dev, "Can't map interrupt.\n");
  497                         return (0);
  498                 } else if ((bus_setup_intr(dev, sc->intr_res, INTR_TYPE_CLK,
  499                     rtc_intr, NULL, sc, &sc->intr_handler))) {
  500                         device_printf(dev, "Can't setup interrupt.\n");
  501                         return (0);
  502                 } else { 
  503                         /* Bind IRQ to BSP to avoid live migration. */
  504                         bus_bind_intr(dev, sc->intr_res, 0);
  505                 }
  506                 sc->et.et_name = "RTC";
  507                 sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_POW2DIV;
  508                 sc->et.et_quality = 0;
  509                 sc->et.et_frequency = 32768;
  510                 sc->et.et_min_period = 0x00080000;
  511                 sc->et.et_max_period = 0x80000000;
  512                 sc->et.et_start = rtc_start;
  513                 sc->et.et_stop = rtc_stop;
  514                 sc->et.et_priv = dev;
  515                 et_register(&sc->et);
  516         }
  517         return(0);
  518 }
  519 
  520 static int
  521 atrtc_isa_attach(device_t dev)
  522 {
  523 
  524         return (atrtc_attach(dev));
  525 }
  526 
  527 #ifdef DEV_ACPI
  528 static int
  529 atrtc_acpi_attach(device_t dev)
  530 {
  531         int ret;
  532 
  533         ret = atrtc_attach(dev);
  534         if (ret)
  535                 return (ret);
  536 
  537         (void)atrtc_reg_acpi_cmos_handler(dev);
  538 
  539         return (0);
  540 }
  541 
  542 static int
  543 atrtc_acpi_detach(device_t dev)
  544 {
  545 
  546         (void)atrtc_unreg_acpi_cmos_handler(dev);
  547         return (0);
  548 }
  549 #endif  /* DEV_ACPI */
  550 
  551 static int
  552 atrtc_resume(device_t dev)
  553 {
  554 
  555         atrtc_restore();
  556         return(0);
  557 }
  558 
  559 static int
  560 atrtc_settime(device_t dev __unused, struct timespec *ts)
  561 {
  562         struct bcd_clocktime bct;
  563 
  564         clock_ts_to_bcd(ts, &bct, false);
  565         clock_dbgprint_bcd(dev, CLOCK_DBG_WRITE, &bct);
  566 
  567         mtx_lock(&atrtc_time_lock);
  568         mtx_lock_spin(&atrtc_lock);
  569 
  570         /* Disable RTC updates and interrupts.  */
  571         rtcout_locked(RTC_STATUSB, RTCSB_HALT | RTCSB_24HR);
  572 
  573         /* Write all the time registers. */
  574         rtcout_locked(RTC_SEC,   bct.sec);
  575         rtcout_locked(RTC_MIN,   bct.min);
  576         rtcout_locked(RTC_HRS,   bct.hour);
  577         rtcout_locked(RTC_WDAY,  bct.dow + 1);
  578         rtcout_locked(RTC_DAY,   bct.day);
  579         rtcout_locked(RTC_MONTH, bct.mon);
  580         rtcout_locked(RTC_YEAR,  bct.year & 0xff);
  581         if (rtc_century)
  582                 rtcout_locked(rtc_century, bct.year >> 8);
  583 
  584         /*
  585          * Re-enable RTC updates and interrupts.
  586          */
  587         rtcout_locked(RTC_STATUSB, rtc_statusb);
  588         rtcin_locked(RTC_INTR);
  589 
  590         mtx_unlock_spin(&atrtc_lock);
  591         mtx_unlock(&atrtc_time_lock);
  592 
  593         return (0);
  594 }
  595 
  596 static int
  597 atrtc_gettime(device_t dev, struct timespec *ts)
  598 {
  599         struct bcd_clocktime bct;
  600 
  601         /* Look if we have a RTC present and the time is valid */
  602         if (!(rtcin(RTC_STATUSD) & RTCSD_PWR)) {
  603                 device_printf(dev, "WARNING: Battery failure indication\n");
  604                 return (EINVAL);
  605         }
  606 
  607         /*
  608          * wait for time update to complete
  609          * If RTCSA_TUP is zero, we have at least 244us before next update.
  610          * This is fast enough on most hardware, but a refinement would be
  611          * to make sure that no more than 240us pass after we start reading,
  612          * and try again if so.
  613          */
  614         mtx_lock(&atrtc_time_lock);
  615         while (rtcin(RTC_STATUSA) & RTCSA_TUP)
  616                 continue;
  617         mtx_lock_spin(&atrtc_lock);
  618         bct.sec  = rtcin_locked(RTC_SEC);
  619         bct.min  = rtcin_locked(RTC_MIN);
  620         bct.hour = rtcin_locked(RTC_HRS);
  621         bct.day  = rtcin_locked(RTC_DAY);
  622         bct.mon  = rtcin_locked(RTC_MONTH);
  623         bct.year = rtcin_locked(RTC_YEAR);
  624         if (rtc_century)
  625                 bct.year |= rtcin_locked(rtc_century) << 8;
  626         mtx_unlock_spin(&atrtc_lock);
  627         mtx_unlock(&atrtc_time_lock);
  628         /* dow is unused in timespec conversion and we have no nsec info. */
  629         bct.dow  = 0;
  630         bct.nsec = 0;
  631         clock_dbgprint_bcd(dev, CLOCK_DBG_READ, &bct);
  632         return (clock_bcd_to_ts(&bct, ts, false));
  633 }
  634 
  635 static device_method_t atrtc_isa_methods[] = {
  636         /* Device interface */
  637         DEVMETHOD(device_probe,         atrtc_probe),
  638         DEVMETHOD(device_attach,        atrtc_isa_attach),
  639         DEVMETHOD(device_detach,        bus_generic_detach),
  640         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  641         DEVMETHOD(device_suspend,       bus_generic_suspend),
  642                 /* XXX stop statclock? */
  643         DEVMETHOD(device_resume,        atrtc_resume),
  644 
  645         /* clock interface */
  646         DEVMETHOD(clock_gettime,        atrtc_gettime),
  647         DEVMETHOD(clock_settime,        atrtc_settime),
  648         { 0, 0 }
  649 };
  650 
  651 static driver_t atrtc_isa_driver = {
  652         "atrtc",
  653         atrtc_isa_methods,
  654         sizeof(struct atrtc_softc),
  655 };
  656 
  657 #ifdef DEV_ACPI
  658 static device_method_t atrtc_acpi_methods[] = {
  659         /* Device interface */
  660         DEVMETHOD(device_probe,         atrtc_probe),
  661         DEVMETHOD(device_attach,        atrtc_acpi_attach),
  662         DEVMETHOD(device_detach,        atrtc_acpi_detach),
  663                 /* XXX stop statclock? */
  664         DEVMETHOD(device_resume,        atrtc_resume),
  665 
  666         /* clock interface */
  667         DEVMETHOD(clock_gettime,        atrtc_gettime),
  668         DEVMETHOD(clock_settime,        atrtc_settime),
  669         { 0, 0 }
  670 };
  671 
  672 static driver_t atrtc_acpi_driver = {
  673         "atrtc",
  674         atrtc_acpi_methods,
  675         sizeof(struct atrtc_softc),
  676 };
  677 #endif  /* DEV_ACPI */
  678 
  679 DRIVER_MODULE(atrtc, isa, atrtc_isa_driver, 0, 0);
  680 #ifdef DEV_ACPI
  681 DRIVER_MODULE(atrtc, acpi, atrtc_acpi_driver, 0, 0);
  682 #endif
  683 ISA_PNP_INFO(atrtc_ids);

Cache object: d0d92cc5b0521bfcc70f2f49f4362789


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