/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- lser_irq
- lser_write
- lser_poll_until_write
- lser_writepolled
- lser_startpolling
- lser_endpolling
- 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 }