Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
script3r
GitHub Repository: script3r/os161
Path: blob/master/kern/dev/lamebus/lser.c
2100 views
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
}
202
203