root/kern/dev/lamebus/lser.c

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

DEFINITIONS

This source file includes following definitions.
  1. lser_irq
  2. lser_write
  3. lser_poll_until_write
  4. lser_writepolled
  5. lser_startpolling
  6. lser_endpolling
  7. config_lser

   1 /*
   2  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
   3  *      The President and Fellows of Harvard College.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. Neither the name of the University nor the names of its contributors
  14  *    may be used to endorse or promote products derived from this software
  15  *    without specific prior written permission.
  16  *
  17  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY 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 UNIVERSITY 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 
  30 #include <types.h>
  31 #include <lib.h>
  32 #include <spinlock.h>
  33 #include <platform/bus.h>
  34 #include <lamebus/lser.h>
  35 #include "autoconf.h"
  36 
  37 /* Registers (offsets within slot) */
  38 #define LSER_REG_CHAR  0     /* Character in/out */
  39 #define LSER_REG_WIRQ  4     /* Write interrupt status */
  40 #define LSER_REG_RIRQ  8     /* Read interrupt status */
  41 
  42 /* Bits in the IRQ registers */
  43 #define LSER_IRQ_ENABLE  1
  44 #define LSER_IRQ_ACTIVE  2
  45 
  46 void
  47 lser_irq(void *vsc)
  48 {
  49         struct lser_softc *sc = vsc;
  50         uint32_t x;
  51         bool clear_to_write = false;
  52         bool got_a_read = false;
  53         uint32_t ch = 0;
  54 
  55         spinlock_acquire(&sc->ls_lock);
  56 
  57         x = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_WIRQ);
  58         if (x & LSER_IRQ_ACTIVE) {
  59                 x = LSER_IRQ_ENABLE;
  60                 sc->ls_wbusy = 0;
  61                 clear_to_write = true;
  62                 bus_write_register(sc->ls_busdata, sc->ls_buspos,
  63                                    LSER_REG_WIRQ, x);
  64         }
  65 
  66         x = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_RIRQ);
  67         if (x & LSER_IRQ_ACTIVE) {
  68                 x = LSER_IRQ_ENABLE;
  69                 ch = bus_read_register(sc->ls_busdata, sc->ls_buspos,
  70                                        LSER_REG_CHAR);
  71                 got_a_read = true;
  72                 bus_write_register(sc->ls_busdata, sc->ls_buspos, 
  73                                    LSER_REG_RIRQ, x);
  74         }
  75 
  76         spinlock_release(&sc->ls_lock);
  77 
  78         if (clear_to_write && sc->ls_start != NULL) {
  79                 sc->ls_start(sc->ls_devdata);
  80         }
  81         if (got_a_read && sc->ls_input != NULL) {
  82                 sc->ls_input(sc->ls_devdata, ch);
  83         }
  84 }
  85 
  86 void
  87 lser_write(void *vls, int ch)
  88 {
  89         struct lser_softc *ls = vls;
  90 
  91         spinlock_acquire(&ls->ls_lock);
  92 
  93         if (ls->ls_wbusy) {
  94                 /*
  95                  * We're not clear to write.
  96                  *
  97                  * This should not happen. It's the job of the driver
  98                  * attached to us to not write until we call
  99                  * ls->ls_start.
 100                  *
 101                  * (Note: if we're the console, the panic will go to
 102                  * lser_writepolled for printing, because we hold a
 103                  * spinlock and interrupts are off; it won't recurse.)
 104                  */
 105                 panic("lser: Not clear to write\n");
 106         }
 107         ls->ls_wbusy = true;
 108 
 109         bus_write_register(ls->ls_busdata, ls->ls_buspos, LSER_REG_CHAR, ch);
 110 
 111         spinlock_release(&ls->ls_lock);
 112 }
 113 
 114 static
 115 void
 116 lser_poll_until_write(struct lser_softc *sc)
 117 {
 118         uint32_t val;
 119 
 120         KASSERT(spinlock_do_i_hold(&sc->ls_lock));
 121 
 122         do {
 123                 val = bus_read_register(sc->ls_busdata, sc->ls_buspos,
 124                                         LSER_REG_WIRQ);
 125         }
 126         while ((val & LSER_IRQ_ACTIVE) == 0);
 127 }
 128 
 129 void
 130 lser_writepolled(void *vsc, int ch)
 131 {
 132         struct lser_softc *sc = vsc;
 133         bool irqpending = false;
 134 
 135         spinlock_acquire(&sc->ls_lock);
 136 
 137         if (sc->ls_wbusy) {
 138                 irqpending = true;
 139                 lser_poll_until_write(sc);
 140                 /* Clear the ready condition */
 141                 bus_write_register(sc->ls_busdata, sc->ls_buspos,
 142                                    LSER_REG_WIRQ, LSER_IRQ_ENABLE);
 143         }
 144 
 145         /* Send the character. */
 146         bus_write_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_CHAR, ch);
 147 
 148         /* Wait until it's done. */
 149         lser_poll_until_write(sc);
 150 
 151         /*
 152          * If there wasn't already an IRQ pending, clear the ready condition.
 153          * But if there was, leave the ready condition, so we get to the 
 154          * interrupt handler in due course.
 155          */
 156         if (!irqpending) {
 157                 bus_write_register(sc->ls_busdata, sc->ls_buspos,
 158                                    LSER_REG_WIRQ, LSER_IRQ_ENABLE);
 159         }
 160 
 161         spinlock_release(&sc->ls_lock);
 162 }
 163 
 164 /*
 165  * Mask the interrupt while we're writing in polling mode. Doing so
 166  * causes the interrupt line to flap on every character, which makes
 167  * the CPU receiving those interrupts upset.
 168  */
 169 void
 170 lser_startpolling(void *vsc)
 171 {
 172         struct lser_softc *sc = vsc;
 173         sc->ls_maskinterrupt(sc->ls_busdata, sc->ls_buspos);
 174 }
 175 
 176 void
 177 lser_endpolling(void *vsc)
 178 {
 179         struct lser_softc *sc = vsc;
 180         sc->ls_unmaskinterrupt(sc->ls_busdata, sc->ls_buspos);
 181 }
 182 
 183 int
 184 config_lser(struct lser_softc *sc, int lserno)
 185 {
 186         (void)lserno;
 187 
 188         /*
 189          * Enable interrupting.
 190          */
 191 
 192         spinlock_init(&sc->ls_lock);
 193         sc->ls_wbusy = false;
 194 
 195         bus_write_register(sc->ls_busdata, sc->ls_buspos,
 196                            LSER_REG_RIRQ, LSER_IRQ_ENABLE);
 197         bus_write_register(sc->ls_busdata, sc->ls_buspos,
 198                            LSER_REG_WIRQ, LSER_IRQ_ENABLE);
 199 
 200         return 0;
 201 }

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