source: mainline/kernel/genarch/src/drivers/via-cuda/cuda.c@ a35b458

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 8.7 KB
Line 
1/*
2 * Copyright (c) 2006 Martin Decky
3 * Copyright (c) 2009 Jiri Svoboda
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup genarch
31 * @{
32 */
33/** @file
34 */
35
36#include <assert.h>
37#include <genarch/drivers/via-cuda/cuda.h>
38#include <console/chardev.h>
39#include <ddi/irq.h>
40#include <arch/asm.h>
41#include <mm/slab.h>
42#include <synch/spinlock.h>
43#include <mem.h>
44
45static irq_ownership_t cuda_claim(irq_t *irq);
46static void cuda_irq_handler(irq_t *irq);
47
48static void cuda_irq_listen(irq_t *irq);
49static void cuda_irq_receive(irq_t *irq);
50static void cuda_irq_rcv_end(irq_t *irq, void *buf, size_t *len);
51static void cuda_irq_send_start(irq_t *irq);
52static void cuda_irq_send(irq_t *irq);
53
54static void cuda_packet_handle(cuda_instance_t *instance, uint8_t *buf, size_t len);
55static void cuda_send_start(cuda_instance_t *instance);
56static void cuda_autopoll_set(cuda_instance_t *instance, bool enable);
57
58/** B register fields */
59enum {
60 TREQ = 0x08,
61 TACK = 0x10,
62 TIP = 0x20
63};
64
65/** IER register fields */
66enum {
67 IER_CLR = 0x00,
68 IER_SET = 0x80,
69
70 SR_INT = 0x04,
71 ALL_INT = 0x7f
72};
73
74/** ACR register fields */
75enum {
76 SR_OUT = 0x10
77};
78
79/** Packet types */
80enum {
81 PT_ADB = 0x00,
82 PT_CUDA = 0x01
83};
84
85/** CUDA packet types */
86enum {
87 CPT_AUTOPOLL = 0x01
88};
89
90cuda_instance_t *cuda_init(cuda_t *dev, inr_t inr, cir_t cir, void *cir_arg)
91{
92 cuda_instance_t *instance
93 = malloc(sizeof(cuda_instance_t), FRAME_ATOMIC);
94 if (instance) {
95 instance->cuda = dev;
96 instance->kbrdin = NULL;
97 instance->xstate = cx_listen;
98 instance->bidx = 0;
99 instance->snd_bytes = 0;
100
101 spinlock_initialize(&instance->dev_lock, "cuda.instance.dev_lock");
102
103 /* Disable all interrupts from CUDA. */
104 pio_write_8(&dev->ier, IER_CLR | ALL_INT);
105
106 irq_initialize(&instance->irq);
107 instance->irq.inr = inr;
108 instance->irq.claim = cuda_claim;
109 instance->irq.handler = cuda_irq_handler;
110 instance->irq.instance = instance;
111 instance->irq.cir = cir;
112 instance->irq.cir_arg = cir_arg;
113 instance->irq.preack = true;
114 }
115
116 return instance;
117}
118
119#include <log.h>
120void cuda_wire(cuda_instance_t *instance, indev_t *kbrdin)
121{
122 cuda_t *dev = instance->cuda;
123
124 assert(instance);
125 assert(kbrdin);
126
127 instance->kbrdin = kbrdin;
128 irq_register(&instance->irq);
129
130 /* Enable SR interrupt. */
131 pio_write_8(&dev->ier, TIP | TREQ);
132 pio_write_8(&dev->ier, IER_SET | SR_INT);
133
134 /* Enable ADB autopolling. */
135 cuda_autopoll_set(instance, true);
136}
137
138static irq_ownership_t cuda_claim(irq_t *irq)
139{
140 cuda_instance_t *instance = irq->instance;
141 cuda_t *dev = instance->cuda;
142 uint8_t ifr;
143
144 spinlock_lock(&instance->dev_lock);
145 ifr = pio_read_8(&dev->ifr);
146 spinlock_unlock(&instance->dev_lock);
147
148 if ((ifr & SR_INT) == 0)
149 return IRQ_DECLINE;
150
151 return IRQ_ACCEPT;
152}
153
154static void cuda_irq_handler(irq_t *irq)
155{
156 cuda_instance_t *instance = irq->instance;
157 uint8_t rbuf[CUDA_RCV_BUF_SIZE];
158 size_t len;
159 bool handle;
160
161 handle = false;
162 len = 0;
163
164 spinlock_lock(&instance->dev_lock);
165
166 /* Lower IFR.SR_INT so that CUDA can generate next int by raising it. */
167 pio_write_8(&instance->cuda->ifr, SR_INT);
168
169 switch (instance->xstate) {
170 case cx_listen: cuda_irq_listen(irq); break;
171 case cx_receive: cuda_irq_receive(irq); break;
172 case cx_rcv_end: cuda_irq_rcv_end(irq, rbuf, &len);
173 handle = true; break;
174 case cx_send_start: cuda_irq_send_start(irq); break;
175 case cx_send: cuda_irq_send(irq); break;
176 }
177
178 spinlock_unlock(&instance->dev_lock);
179
180 /* Handle an incoming packet. */
181 if (handle)
182 cuda_packet_handle(instance, rbuf, len);
183}
184
185/** Interrupt in listen state.
186 *
187 * Start packet reception.
188 */
189static void cuda_irq_listen(irq_t *irq)
190{
191 cuda_instance_t *instance = irq->instance;
192 cuda_t *dev = instance->cuda;
193 uint8_t b;
194
195 b = pio_read_8(&dev->b);
196
197 if ((b & TREQ) != 0) {
198 log(LF_OTHER, LVL_ERROR, "cuda_irq_listen: no TREQ?!");
199 return;
200 }
201
202 pio_read_8(&dev->sr);
203 pio_write_8(&dev->b, pio_read_8(&dev->b) & ~TIP);
204 instance->xstate = cx_receive;
205}
206
207/** Interrupt in receive state.
208 *
209 * Receive next byte of packet.
210 */
211static void cuda_irq_receive(irq_t *irq)
212{
213 cuda_instance_t *instance = irq->instance;
214 cuda_t *dev = instance->cuda;
215 uint8_t b, data;
216
217 data = pio_read_8(&dev->sr);
218 if (instance->bidx < CUDA_RCV_BUF_SIZE)
219 instance->rcv_buf[instance->bidx++] = data;
220
221 b = pio_read_8(&dev->b);
222
223 if ((b & TREQ) == 0) {
224 pio_write_8(&dev->b, b ^ TACK);
225 } else {
226 pio_write_8(&dev->b, b | TACK | TIP);
227 instance->xstate = cx_rcv_end;
228 }
229}
230
231/** Interrupt in rcv_end state.
232 *
233 * Terminate packet reception. Either go back to listen state or start
234 * receiving another packet if CUDA has one for us.
235 */
236static void cuda_irq_rcv_end(irq_t *irq, void *buf, size_t *len)
237{
238 cuda_instance_t *instance = irq->instance;
239 cuda_t *dev = instance->cuda;
240 uint8_t b;
241
242 b = pio_read_8(&dev->b);
243 pio_read_8(&dev->sr);
244
245 if ((b & TREQ) == 0) {
246 instance->xstate = cx_receive;
247 pio_write_8(&dev->b, b & ~TIP);
248 } else {
249 instance->xstate = cx_listen;
250 cuda_send_start(instance);
251 }
252
253 memcpy(buf, instance->rcv_buf, instance->bidx);
254 *len = instance->bidx;
255 instance->bidx = 0;
256}
257
258/** Interrupt in send_start state.
259 *
260 * Process result of sending first byte (and send second on success).
261 */
262static void cuda_irq_send_start(irq_t *irq)
263{
264 cuda_instance_t *instance = irq->instance;
265 cuda_t *dev = instance->cuda;
266 uint8_t b;
267
268 b = pio_read_8(&dev->b);
269
270 if ((b & TREQ) == 0) {
271 /* Collision */
272 pio_write_8(&dev->acr, pio_read_8(&dev->acr) & ~SR_OUT);
273 pio_read_8(&dev->sr);
274 pio_write_8(&dev->b, pio_read_8(&dev->b) | TIP | TACK);
275 instance->xstate = cx_listen;
276 return;
277 }
278
279 pio_write_8(&dev->sr, instance->snd_buf[1]);
280 pio_write_8(&dev->b, pio_read_8(&dev->b) ^ TACK);
281 instance->bidx = 2;
282
283 instance->xstate = cx_send;
284}
285
286/** Interrupt in send state.
287 *
288 * Send next byte or terminate transmission.
289 */
290static void cuda_irq_send(irq_t *irq)
291{
292 cuda_instance_t *instance = irq->instance;
293 cuda_t *dev = instance->cuda;
294
295 if (instance->bidx < instance->snd_bytes) {
296 /* Send next byte. */
297 pio_write_8(&dev->sr, instance->snd_buf[instance->bidx++]);
298 pio_write_8(&dev->b, pio_read_8(&dev->b) ^ TACK);
299 return;
300 }
301
302 /* End transfer. */
303 instance->snd_bytes = 0;
304 instance->bidx = 0;
305
306 pio_write_8(&dev->acr, pio_read_8(&dev->acr) & ~SR_OUT);
307 pio_read_8(&dev->sr);
308 pio_write_8(&dev->b, pio_read_8(&dev->b) | TACK | TIP);
309
310 instance->xstate = cx_listen;
311 /* TODO: Match reply with request. */
312}
313
314static void cuda_packet_handle(cuda_instance_t *instance, uint8_t *data, size_t len)
315{
316 if (data[0] != 0x00 || data[1] != 0x40 || (data[2] != 0x2c
317 && data[2] != 0x8c))
318 return;
319
320 /* The packet contains one or two scancodes. */
321 if (data[3] != 0xff)
322 indev_push_character(instance->kbrdin, data[3]);
323 if (data[4] != 0xff)
324 indev_push_character(instance->kbrdin, data[4]);
325}
326
327static void cuda_autopoll_set(cuda_instance_t *instance, bool enable)
328{
329 instance->snd_buf[0] = PT_CUDA;
330 instance->snd_buf[1] = CPT_AUTOPOLL;
331 instance->snd_buf[2] = enable ? 0x01 : 0x00;
332 instance->snd_bytes = 3;
333 instance->bidx = 0;
334
335 cuda_send_start(instance);
336}
337
338static void cuda_send_start(cuda_instance_t *instance)
339{
340 cuda_t *dev = instance->cuda;
341
342 assert(instance->xstate == cx_listen);
343
344 if (instance->snd_bytes == 0)
345 return;
346
347 /* Check for incoming data. */
348 if ((pio_read_8(&dev->b) & TREQ) == 0)
349 return;
350
351 pio_write_8(&dev->acr, pio_read_8(&dev->acr) | SR_OUT);
352 pio_write_8(&dev->sr, instance->snd_buf[0]);
353 pio_write_8(&dev->b, pio_read_8(&dev->b) & ~TIP);
354
355 instance->xstate = cx_send_start;
356}
357
358
359/** @}
360 */
Note: See TracBrowser for help on using the repository browser.