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/clock.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) 1990 The Regents of the University of California.
    3  * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org>
    4  * All rights reserved.
    5  *
    6  * This code is derived from software contributed to Berkeley by
    7  * William Jolitz and Don Ahn.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 4. Neither the name of the University nor the names of its contributors
   18  *    may be used to endorse or promote products derived from this software
   19  *    without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  *
   33  *      from: @(#)clock.c       7.2 (Berkeley) 5/12/91
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD: releng/10.4/sys/x86/isa/clock.c 254373 2013-08-15 17:21:06Z brooks $");
   38 
   39 /*
   40  * Routines to handle clock hardware.
   41  */
   42 
   43 #include "opt_clock.h"
   44 #include "opt_isa.h"
   45 #include "opt_mca.h"
   46 
   47 #include <sys/param.h>
   48 #include <sys/systm.h>
   49 #include <sys/bus.h>
   50 #include <sys/lock.h>
   51 #include <sys/kdb.h>
   52 #include <sys/mutex.h>
   53 #include <sys/proc.h>
   54 #include <sys/kernel.h>
   55 #include <sys/module.h>
   56 #include <sys/rman.h>
   57 #include <sys/sched.h>
   58 #include <sys/smp.h>
   59 #include <sys/sysctl.h>
   60 #include <sys/timeet.h>
   61 #include <sys/timetc.h>
   62 
   63 #include <machine/clock.h>
   64 #include <machine/cpu.h>
   65 #include <machine/intr_machdep.h>
   66 #include <machine/ppireg.h>
   67 #include <machine/timerreg.h>
   68 
   69 #ifdef PC98
   70 #include <pc98/pc98/pc98_machdep.h>
   71 #else
   72 #include <isa/rtc.h>
   73 #endif
   74 #ifdef DEV_ISA
   75 #ifdef PC98
   76 #include <pc98/cbus/cbus.h>
   77 #else
   78 #include <isa/isareg.h>
   79 #endif
   80 #include <isa/isavar.h>
   81 #endif
   82 
   83 #ifdef DEV_MCA
   84 #include <i386/bios/mca_machdep.h>
   85 #endif
   86 
   87 int     clkintr_pending;
   88 #ifndef TIMER_FREQ
   89 #ifdef PC98
   90 #define TIMER_FREQ   2457600
   91 #else
   92 #define TIMER_FREQ   1193182
   93 #endif
   94 #endif
   95 u_int   i8254_freq = TIMER_FREQ;
   96 TUNABLE_INT("hw.i8254.freq", &i8254_freq);
   97 int     i8254_max_count;
   98 static int i8254_timecounter = 1;
   99 
  100 struct mtx clock_lock;
  101 static  struct intsrc *i8254_intsrc;
  102 static  uint16_t i8254_lastcount;
  103 static  uint16_t i8254_offset;
  104 static  int     (*i8254_pending)(struct intsrc *);
  105 static  int     i8254_ticked;
  106 
  107 struct attimer_softc {
  108         int intr_en;
  109         int port_rid, intr_rid;
  110         struct resource *port_res;
  111         struct resource *intr_res;
  112 #ifdef PC98
  113         int port_rid2;
  114         struct resource *port_res2;
  115 #endif
  116         void *intr_handler;
  117         struct timecounter tc;
  118         struct eventtimer et;
  119         int             mode;
  120 #define MODE_STOP       0
  121 #define MODE_PERIODIC   1
  122 #define MODE_ONESHOT    2
  123         uint32_t        period;
  124 };
  125 static struct attimer_softc *attimer_sc = NULL;
  126 
  127 static int timer0_period = -2;
  128 static int timer0_mode = 0xffff;
  129 static int timer0_last = 0xffff;
  130 
  131 /* Values for timerX_state: */
  132 #define RELEASED        0
  133 #define RELEASE_PENDING 1
  134 #define ACQUIRED        2
  135 #define ACQUIRE_PENDING 3
  136 
  137 static  u_char  timer2_state;
  138 
  139 static  unsigned i8254_get_timecount(struct timecounter *tc);
  140 static  void    set_i8254_freq(int mode, uint32_t period);
  141 
  142 static int
  143 clkintr(void *arg)
  144 {
  145         struct attimer_softc *sc = (struct attimer_softc *)arg;
  146 
  147         if (i8254_timecounter && sc->period != 0) {
  148                 mtx_lock_spin(&clock_lock);
  149                 if (i8254_ticked)
  150                         i8254_ticked = 0;
  151                 else {
  152                         i8254_offset += i8254_max_count;
  153                         i8254_lastcount = 0;
  154                 }
  155                 clkintr_pending = 0;
  156                 mtx_unlock_spin(&clock_lock);
  157         }
  158 
  159         if (sc && sc->et.et_active && sc->mode != MODE_STOP)
  160                 sc->et.et_event_cb(&sc->et, sc->et.et_arg);
  161 
  162 #ifdef DEV_MCA
  163         /* Reset clock interrupt by asserting bit 7 of port 0x61 */
  164         if (MCA_system)
  165                 outb(0x61, inb(0x61) | 0x80);
  166 #endif
  167         return (FILTER_HANDLED);
  168 }
  169 
  170 int
  171 timer_spkr_acquire(void)
  172 {
  173         int mode;
  174 
  175 #ifdef PC98
  176         mode = TIMER_SEL1 | TIMER_SQWAVE | TIMER_16BIT;
  177 #else
  178         mode = TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT;
  179 #endif
  180 
  181         if (timer2_state != RELEASED)
  182                 return (-1);
  183         timer2_state = ACQUIRED;
  184 
  185         /*
  186          * This access to the timer registers is as atomic as possible
  187          * because it is a single instruction.  We could do better if we
  188          * knew the rate.  Use of splclock() limits glitches to 10-100us,
  189          * and this is probably good enough for timer2, so we aren't as
  190          * careful with it as with timer0.
  191          */
  192 #ifdef PC98
  193         outb(TIMER_MODE, TIMER_SEL1 | (mode & 0x3f));
  194 #else
  195         outb(TIMER_MODE, TIMER_SEL2 | (mode & 0x3f));
  196 #endif
  197         ppi_spkr_on();          /* enable counter2 output to speaker */
  198         return (0);
  199 }
  200 
  201 int
  202 timer_spkr_release(void)
  203 {
  204 
  205         if (timer2_state != ACQUIRED)
  206                 return (-1);
  207         timer2_state = RELEASED;
  208 #ifdef PC98
  209         outb(TIMER_MODE, TIMER_SEL1 | TIMER_SQWAVE | TIMER_16BIT);
  210 #else
  211         outb(TIMER_MODE, TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT);
  212 #endif
  213         ppi_spkr_off();         /* disable counter2 output to speaker */
  214         return (0);
  215 }
  216 
  217 void
  218 timer_spkr_setfreq(int freq)
  219 {
  220 
  221         freq = i8254_freq / freq;
  222         mtx_lock_spin(&clock_lock);
  223 #ifdef PC98
  224         outb(TIMER_CNTR1, freq & 0xff);
  225         outb(TIMER_CNTR1, freq >> 8);
  226 #else
  227         outb(TIMER_CNTR2, freq & 0xff);
  228         outb(TIMER_CNTR2, freq >> 8);
  229 #endif
  230         mtx_unlock_spin(&clock_lock);
  231 }
  232 
  233 static int
  234 getit(void)
  235 {
  236         int high, low;
  237 
  238         mtx_lock_spin(&clock_lock);
  239 
  240         /* Select timer0 and latch counter value. */
  241         outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
  242 
  243         low = inb(TIMER_CNTR0);
  244         high = inb(TIMER_CNTR0);
  245 
  246         mtx_unlock_spin(&clock_lock);
  247         return ((high << 8) | low);
  248 }
  249 
  250 #ifndef DELAYDEBUG
  251 static u_int
  252 get_tsc(__unused struct timecounter *tc)
  253 {
  254 
  255         return (rdtsc32());
  256 }
  257 
  258 static __inline int
  259 delay_tc(int n)
  260 {
  261         struct timecounter *tc;
  262         timecounter_get_t *func;
  263         uint64_t end, freq, now;
  264         u_int last, mask, u;
  265 
  266         tc = timecounter;
  267         freq = atomic_load_acq_64(&tsc_freq);
  268         if (tsc_is_invariant && freq != 0) {
  269                 func = get_tsc;
  270                 mask = ~0u;
  271         } else {
  272                 if (tc->tc_quality <= 0)
  273                         return (0);
  274                 func = tc->tc_get_timecount;
  275                 mask = tc->tc_counter_mask;
  276                 freq = tc->tc_frequency;
  277         }
  278         now = 0;
  279         end = freq * n / 1000000;
  280         if (func == get_tsc)
  281                 sched_pin();
  282         last = func(tc) & mask;
  283         do {
  284                 cpu_spinwait();
  285                 u = func(tc) & mask;
  286                 if (u < last)
  287                         now += mask - last + u + 1;
  288                 else
  289                         now += u - last;
  290                 last = u;
  291         } while (now < end);
  292         if (func == get_tsc)
  293                 sched_unpin();
  294         return (1);
  295 }
  296 #endif
  297 
  298 /*
  299  * Wait "n" microseconds.
  300  * Relies on timer 1 counting down from (i8254_freq / hz)
  301  * Note: timer had better have been programmed before this is first used!
  302  */
  303 void
  304 DELAY(int n)
  305 {
  306         int delta, prev_tick, tick, ticks_left;
  307 #ifdef DELAYDEBUG
  308         int getit_calls = 1;
  309         int n1;
  310         static int state = 0;
  311 
  312         if (state == 0) {
  313                 state = 1;
  314                 for (n1 = 1; n1 <= 10000000; n1 *= 10)
  315                         DELAY(n1);
  316                 state = 2;
  317         }
  318         if (state == 1)
  319                 printf("DELAY(%d)...", n);
  320 #else
  321         if (delay_tc(n))
  322                 return;
  323 #endif
  324         /*
  325          * Read the counter first, so that the rest of the setup overhead is
  326          * counted.  Guess the initial overhead is 20 usec (on most systems it
  327          * takes about 1.5 usec for each of the i/o's in getit().  The loop
  328          * takes about 6 usec on a 486/33 and 13 usec on a 386/20.  The
  329          * multiplications and divisions to scale the count take a while).
  330          *
  331          * However, if ddb is active then use a fake counter since reading
  332          * the i8254 counter involves acquiring a lock.  ddb must not do
  333          * locking for many reasons, but it calls here for at least atkbd
  334          * input.
  335          */
  336 #ifdef KDB
  337         if (kdb_active)
  338                 prev_tick = 1;
  339         else
  340 #endif
  341                 prev_tick = getit();
  342         n -= 0;                 /* XXX actually guess no initial overhead */
  343         /*
  344          * Calculate (n * (i8254_freq / 1e6)) without using floating point
  345          * and without any avoidable overflows.
  346          */
  347         if (n <= 0)
  348                 ticks_left = 0;
  349         else if (n < 256)
  350                 /*
  351                  * Use fixed point to avoid a slow division by 1000000.
  352                  * 39099 = 1193182 * 2^15 / 10^6 rounded to nearest.
  353                  * 2^15 is the first power of 2 that gives exact results
  354                  * for n between 0 and 256.
  355                  */
  356                 ticks_left = ((u_int)n * 39099 + (1 << 15) - 1) >> 15;
  357         else
  358                 /*
  359                  * Don't bother using fixed point, although gcc-2.7.2
  360                  * generates particularly poor code for the long long
  361                  * division, since even the slow way will complete long
  362                  * before the delay is up (unless we're interrupted).
  363                  */
  364                 ticks_left = ((u_int)n * (long long)i8254_freq + 999999)
  365                              / 1000000;
  366 
  367         while (ticks_left > 0) {
  368 #ifdef KDB
  369                 if (kdb_active) {
  370 #ifdef PC98
  371                         outb(0x5f, 0);
  372 #else
  373                         inb(0x84);
  374 #endif
  375                         tick = prev_tick - 1;
  376                         if (tick <= 0)
  377                                 tick = i8254_max_count;
  378                 } else
  379 #endif
  380                         tick = getit();
  381 #ifdef DELAYDEBUG
  382                 ++getit_calls;
  383 #endif
  384                 delta = prev_tick - tick;
  385                 prev_tick = tick;
  386                 if (delta < 0) {
  387                         delta += i8254_max_count;
  388                         /*
  389                          * Guard against i8254_max_count being wrong.
  390                          * This shouldn't happen in normal operation,
  391                          * but it may happen if set_i8254_freq() is
  392                          * traced.
  393                          */
  394                         if (delta < 0)
  395                                 delta = 0;
  396                 }
  397                 ticks_left -= delta;
  398         }
  399 #ifdef DELAYDEBUG
  400         if (state == 1)
  401                 printf(" %d calls to getit() at %d usec each\n",
  402                        getit_calls, (n + 5) / getit_calls);
  403 #endif
  404 }
  405 
  406 static void
  407 set_i8254_freq(int mode, uint32_t period)
  408 {
  409         int new_count, new_mode;
  410 
  411         mtx_lock_spin(&clock_lock);
  412         if (mode == MODE_STOP) {
  413                 if (i8254_timecounter) {
  414                         mode = MODE_PERIODIC;
  415                         new_count = 0x10000;
  416                 } else
  417                         new_count = -1;
  418         } else {
  419                 new_count = min(((uint64_t)i8254_freq * period +
  420                     0x80000000LLU) >> 32, 0x10000);
  421         }
  422         if (new_count == timer0_period)
  423                 goto out;
  424         i8254_max_count = ((new_count & ~0xffff) != 0) ? 0xffff : new_count;
  425         timer0_period = (mode == MODE_PERIODIC) ? new_count : -1;
  426         switch (mode) {
  427         case MODE_STOP:
  428                 new_mode = TIMER_SEL0 | TIMER_INTTC | TIMER_16BIT;
  429                 outb(TIMER_MODE, new_mode);
  430                 outb(TIMER_CNTR0, 0);
  431                 outb(TIMER_CNTR0, 0);
  432                 break;
  433         case MODE_PERIODIC:
  434                 new_mode = TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT;
  435                 outb(TIMER_MODE, new_mode);
  436                 outb(TIMER_CNTR0, new_count & 0xff);
  437                 outb(TIMER_CNTR0, new_count >> 8);
  438                 break;
  439         case MODE_ONESHOT:
  440                 if (new_count < 256 && timer0_last < 256) {
  441                         new_mode = TIMER_SEL0 | TIMER_INTTC | TIMER_LSB;
  442                         if (new_mode != timer0_mode)
  443                                 outb(TIMER_MODE, new_mode);
  444                         outb(TIMER_CNTR0, new_count & 0xff);
  445                         break;
  446                 }
  447                 new_mode = TIMER_SEL0 | TIMER_INTTC | TIMER_16BIT;
  448                 if (new_mode != timer0_mode)
  449                         outb(TIMER_MODE, new_mode);
  450                 outb(TIMER_CNTR0, new_count & 0xff);
  451                 outb(TIMER_CNTR0, new_count >> 8);
  452                 break;
  453         default:
  454                 panic("set_i8254_freq: unknown operational mode");
  455         }
  456         timer0_mode = new_mode;
  457         timer0_last = new_count;
  458 out:
  459         mtx_unlock_spin(&clock_lock);
  460 }
  461 
  462 static void
  463 i8254_restore(void)
  464 {
  465 
  466         timer0_period = -2;
  467         timer0_mode = 0xffff;
  468         timer0_last = 0xffff;
  469         if (attimer_sc != NULL)
  470                 set_i8254_freq(attimer_sc->mode, attimer_sc->period);
  471         else
  472                 set_i8254_freq(MODE_STOP, 0);
  473 }
  474 
  475 #ifndef __amd64__
  476 /*
  477  * Restore all the timers non-atomically (XXX: should be atomically).
  478  *
  479  * This function is called from pmtimer_resume() to restore all the timers.
  480  * This should not be necessary, but there are broken laptops that do not
  481  * restore all the timers on resume. The APM spec was at best vague on the
  482  * subject.
  483  * pmtimer is used only with the old APM power management, and not with
  484  * acpi, which is required for amd64, so skip it in that case.
  485  */
  486 void
  487 timer_restore(void)
  488 {
  489 
  490         i8254_restore();                /* restore i8254_freq and hz */
  491 #ifndef PC98
  492         atrtc_restore();                /* reenable RTC interrupts */
  493 #endif
  494 }
  495 #endif
  496 
  497 /* This is separate from startrtclock() so that it can be called early. */
  498 void
  499 i8254_init(void)
  500 {
  501 
  502         mtx_init(&clock_lock, "clk", NULL, MTX_SPIN | MTX_NOPROFILE);
  503 #ifdef PC98
  504         if (pc98_machine_type & M_8M)
  505                 i8254_freq = 1996800L; /* 1.9968 MHz */
  506 #endif
  507         set_i8254_freq(MODE_STOP, 0);
  508 }
  509 
  510 void
  511 startrtclock()
  512 {
  513 
  514         init_TSC();
  515 }
  516 
  517 void
  518 cpu_initclocks(void)
  519 {
  520 
  521         cpu_initclocks_bsp();
  522 }
  523 
  524 static int
  525 sysctl_machdep_i8254_freq(SYSCTL_HANDLER_ARGS)
  526 {
  527         int error;
  528         u_int freq;
  529 
  530         /*
  531          * Use `i8254' instead of `timer' in external names because `timer'
  532          * is too generic.  Should use it everywhere.
  533          */
  534         freq = i8254_freq;
  535         error = sysctl_handle_int(oidp, &freq, 0, req);
  536         if (error == 0 && req->newptr != NULL) {
  537                 i8254_freq = freq;
  538                 if (attimer_sc != NULL) {
  539                         set_i8254_freq(attimer_sc->mode, attimer_sc->period);
  540                         attimer_sc->tc.tc_frequency = freq;
  541                 } else {
  542                         set_i8254_freq(MODE_STOP, 0);
  543                 }
  544         }
  545         return (error);
  546 }
  547 
  548 SYSCTL_PROC(_machdep, OID_AUTO, i8254_freq, CTLTYPE_INT | CTLFLAG_RW,
  549     0, sizeof(u_int), sysctl_machdep_i8254_freq, "IU",
  550     "i8254 timer frequency");
  551 
  552 static unsigned
  553 i8254_get_timecount(struct timecounter *tc)
  554 {
  555         device_t dev = (device_t)tc->tc_priv;
  556         struct attimer_softc *sc = device_get_softc(dev);
  557         register_t flags;
  558         uint16_t count;
  559         u_int high, low;
  560 
  561         if (sc->period == 0)
  562                 return (i8254_max_count - getit());
  563 
  564 #ifdef __amd64__
  565         flags = read_rflags();
  566 #else
  567         flags = read_eflags();
  568 #endif
  569         mtx_lock_spin(&clock_lock);
  570 
  571         /* Select timer0 and latch counter value. */
  572         outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
  573 
  574         low = inb(TIMER_CNTR0);
  575         high = inb(TIMER_CNTR0);
  576         count = i8254_max_count - ((high << 8) | low);
  577         if (count < i8254_lastcount ||
  578             (!i8254_ticked && (clkintr_pending ||
  579             ((count < 20 || (!(flags & PSL_I) &&
  580             count < i8254_max_count / 2u)) &&
  581             i8254_pending != NULL && i8254_pending(i8254_intsrc))))) {
  582                 i8254_ticked = 1;
  583                 i8254_offset += i8254_max_count;
  584         }
  585         i8254_lastcount = count;
  586         count += i8254_offset;
  587         mtx_unlock_spin(&clock_lock);
  588         return (count);
  589 }
  590 
  591 static int
  592 attimer_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
  593 {
  594         device_t dev = (device_t)et->et_priv;
  595         struct attimer_softc *sc = device_get_softc(dev);
  596 
  597         if (period != 0) {
  598                 sc->mode = MODE_PERIODIC;
  599                 sc->period = period;
  600         } else {
  601                 sc->mode = MODE_ONESHOT;
  602                 sc->period = first;
  603         }
  604         if (!sc->intr_en) {
  605                 i8254_intsrc->is_pic->pic_enable_source(i8254_intsrc);
  606                 sc->intr_en = 1;
  607         }
  608         set_i8254_freq(sc->mode, sc->period);
  609         return (0);
  610 }
  611 
  612 static int
  613 attimer_stop(struct eventtimer *et)
  614 {
  615         device_t dev = (device_t)et->et_priv;
  616         struct attimer_softc *sc = device_get_softc(dev);
  617         
  618         sc->mode = MODE_STOP;
  619         sc->period = 0;
  620         set_i8254_freq(sc->mode, sc->period);
  621         return (0);
  622 }
  623 
  624 #ifdef DEV_ISA
  625 /*
  626  * Attach to the ISA PnP descriptors for the timer
  627  */
  628 static struct isa_pnp_id attimer_ids[] = {
  629         { 0x0001d041 /* PNP0100 */, "AT timer" },
  630         { 0 }
  631 };
  632 
  633 #ifdef PC98
  634 static void
  635 pc98_alloc_resource(device_t dev)
  636 {
  637         static bus_addr_t iat1[] = {0, 2, 4, 6};
  638         static bus_addr_t iat2[] = {0, 4};
  639         struct attimer_softc *sc;
  640 
  641         sc = device_get_softc(dev);
  642 
  643         sc->port_rid = 0;
  644         bus_set_resource(dev, SYS_RES_IOPORT, sc->port_rid, IO_TIMER1, 1);
  645         sc->port_res = isa_alloc_resourcev(dev, SYS_RES_IOPORT,
  646             &sc->port_rid, iat1, 4, RF_ACTIVE);
  647         if (sc->port_res == NULL)
  648                 device_printf(dev, "Warning: Couldn't map I/O.\n");
  649         else
  650                 isa_load_resourcev(sc->port_res, iat1, 4);
  651 
  652         sc->port_rid2 = 4;
  653         bus_set_resource(dev, SYS_RES_IOPORT, sc->port_rid2, TIMER_CNTR1, 1);
  654         sc->port_res2 = isa_alloc_resourcev(dev, SYS_RES_IOPORT,
  655             &sc->port_rid2, iat2, 2, RF_ACTIVE);
  656         if (sc->port_res2 == NULL)
  657                 device_printf(dev, "Warning: Couldn't map I/O.\n");
  658         else
  659                 isa_load_resourcev(sc->port_res2, iat2, 2);
  660 }
  661 
  662 static void
  663 pc98_release_resource(device_t dev)
  664 {
  665         struct attimer_softc *sc;
  666 
  667         sc = device_get_softc(dev);
  668 
  669         if (sc->port_res)
  670                 bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid,
  671                     sc->port_res);
  672         if (sc->port_res2)
  673                 bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid2,
  674                     sc->port_res2);
  675 }
  676 #endif
  677 
  678 static int
  679 attimer_probe(device_t dev)
  680 {
  681         int result;
  682         
  683         result = ISA_PNP_PROBE(device_get_parent(dev), dev, attimer_ids);
  684         /* ENOENT means no PnP-ID, device is hinted. */
  685         if (result == ENOENT) {
  686                 device_set_desc(dev, "AT timer");
  687 #ifdef PC98
  688                 /* To print resources correctly. */
  689                 pc98_alloc_resource(dev);
  690                 pc98_release_resource(dev);
  691 #endif
  692                 return (BUS_PROBE_LOW_PRIORITY);
  693         }
  694         return (result);
  695 }
  696 
  697 static int
  698 attimer_attach(device_t dev)
  699 {
  700         struct attimer_softc *sc;
  701         u_long s;
  702         int i;
  703 
  704         attimer_sc = sc = device_get_softc(dev);
  705         bzero(sc, sizeof(struct attimer_softc));
  706 #ifdef PC98
  707         pc98_alloc_resource(dev);
  708 #else
  709         if (!(sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT,
  710             &sc->port_rid, IO_TIMER1, IO_TIMER1 + 3, 4, RF_ACTIVE)))
  711                 device_printf(dev,"Warning: Couldn't map I/O.\n");
  712 #endif
  713         i8254_intsrc = intr_lookup_source(0);
  714         if (i8254_intsrc != NULL)
  715                 i8254_pending = i8254_intsrc->is_pic->pic_source_pending;
  716         resource_int_value(device_get_name(dev), device_get_unit(dev),
  717             "timecounter", &i8254_timecounter);
  718         set_i8254_freq(MODE_STOP, 0);
  719         if (i8254_timecounter) {
  720                 sc->tc.tc_get_timecount = i8254_get_timecount;
  721                 sc->tc.tc_counter_mask = 0xffff;
  722                 sc->tc.tc_frequency = i8254_freq;
  723                 sc->tc.tc_name = "i8254";
  724                 sc->tc.tc_quality = 0;
  725                 sc->tc.tc_priv = dev;
  726                 tc_init(&sc->tc);
  727         }
  728         if (resource_int_value(device_get_name(dev), device_get_unit(dev),
  729             "clock", &i) != 0 || i != 0) {
  730                 sc->intr_rid = 0;
  731                 while (bus_get_resource(dev, SYS_RES_IRQ, sc->intr_rid,
  732                     &s, NULL) == 0 && s != 0)
  733                         sc->intr_rid++;
  734                 if (!(sc->intr_res = bus_alloc_resource(dev, SYS_RES_IRQ,
  735                     &sc->intr_rid, 0, 0, 1, RF_ACTIVE))) {
  736                         device_printf(dev,"Can't map interrupt.\n");
  737                         return (0);
  738                 }
  739                 /* Dirty hack, to make bus_setup_intr to not enable source. */
  740                 i8254_intsrc->is_handlers++;
  741                 if ((bus_setup_intr(dev, sc->intr_res,
  742                     INTR_MPSAFE | INTR_TYPE_CLK,
  743                     (driver_filter_t *)clkintr, NULL,
  744                     sc, &sc->intr_handler))) {
  745                         device_printf(dev, "Can't setup interrupt.\n");
  746                         i8254_intsrc->is_handlers--;
  747                         return (0);
  748                 }
  749                 i8254_intsrc->is_handlers--;
  750                 i8254_intsrc->is_pic->pic_enable_intr(i8254_intsrc);
  751                 sc->et.et_name = "i8254";
  752                 sc->et.et_flags = ET_FLAGS_PERIODIC;
  753                 if (!i8254_timecounter)
  754                         sc->et.et_flags |= ET_FLAGS_ONESHOT;
  755                 sc->et.et_quality = 100;
  756                 sc->et.et_frequency = i8254_freq;
  757                 sc->et.et_min_period = (0x0002LLU << 32) / i8254_freq;
  758                 sc->et.et_max_period = (0xfffeLLU << 32) / i8254_freq;
  759                 sc->et.et_start = attimer_start;
  760                 sc->et.et_stop = attimer_stop;
  761                 sc->et.et_priv = dev;
  762                 et_register(&sc->et);
  763         }
  764         return(0);
  765 }
  766 
  767 static int
  768 attimer_resume(device_t dev)
  769 {
  770 
  771         i8254_restore();
  772         return (0);
  773 }
  774 
  775 static device_method_t attimer_methods[] = {
  776         /* Device interface */
  777         DEVMETHOD(device_probe,         attimer_probe),
  778         DEVMETHOD(device_attach,        attimer_attach),
  779         DEVMETHOD(device_detach,        bus_generic_detach),
  780         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  781         DEVMETHOD(device_suspend,       bus_generic_suspend),
  782         DEVMETHOD(device_resume,        attimer_resume),
  783         { 0, 0 }
  784 };
  785 
  786 static driver_t attimer_driver = {
  787         "attimer",
  788         attimer_methods,
  789         sizeof(struct attimer_softc),
  790 };
  791 
  792 static devclass_t attimer_devclass;
  793 
  794 DRIVER_MODULE(attimer, isa, attimer_driver, attimer_devclass, 0, 0);
  795 DRIVER_MODULE(attimer, acpi, attimer_driver, attimer_devclass, 0, 0);
  796 
  797 #endif /* DEV_ISA */

Cache object: bc2f8589c0680c911c8df5c26c615892


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