]>
Commit | Line | Data |
---|---|---|
c906108c | 1 | /* This file is part of the program GDB, the GNU debugger. |
d3eb0aa2 | 2 | |
1d506c26 | 3 | Copyright (C) 1998-2024 Free Software Foundation, Inc. |
c906108c | 4 | Contributed by Cygnus Solutions. |
d3eb0aa2 | 5 | |
c906108c SS |
6 | This program is free software; you can redistribute it and/or modify |
7 | it under the terms of the GNU General Public License as published by | |
4744ac1b | 8 | the Free Software Foundation; either version 3 of the License, or |
c906108c | 9 | (at your option) any later version. |
4744ac1b | 10 | |
c906108c SS |
11 | This program is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
4744ac1b | 15 | |
c906108c | 16 | You should have received a copy of the GNU General Public License |
4744ac1b | 17 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
d3eb0aa2 | 18 | |
c906108c SS |
19 | */ |
20 | ||
6df01ab8 MF |
21 | /* This must come before any other includes. */ |
22 | #include "defs.h" | |
c906108c SS |
23 | |
24 | #include "sim-main.h" | |
25 | #include "hw-main.h" | |
26 | #include "dv-sockser.h" | |
27 | #include "sim-assert.h" | |
28 | ||
77c0fdb7 | 29 | #include <stdlib.h> |
c906108c SS |
30 | |
31 | /* DEVICE | |
32 | ||
d3eb0aa2 | 33 | |
c906108c SS |
34 | tx3904sio - tx3904 serial I/O |
35 | ||
d3eb0aa2 | 36 | |
c906108c SS |
37 | DESCRIPTION |
38 | ||
d3eb0aa2 | 39 | |
c906108c SS |
40 | Implements one tx3904 serial I/O controller described in the tx3904 |
41 | user guide. Three instances are required for SIO0 and SIO1 within | |
42 | the tx3904, at different base addresses. | |
43 | ||
44 | Both internal and system clocks are synthesized as divided versions | |
45 | of the simulator clock. | |
d3eb0aa2 | 46 | |
c906108c SS |
47 | There is no support for: |
48 | - CTS/RTS flow control | |
49 | - baud rate emulation - use infinite speed instead | |
50 | - general frame format - use 8N1 | |
51 | - multi-controller system | |
52 | - DMA - use interrupt-driven or polled-I/O instead | |
53 | ||
54 | ||
55 | PROPERTIES | |
56 | ||
57 | ||
58 | reg <base> <length> | |
59 | ||
60 | Base of SIO control register bank. <length> must equal 0x100. | |
61 | Register offsets: 0: SLCR: line control register | |
62 | 4: SLSR: line status register | |
63 | 8: SDICR: DMA/interrupt control register | |
64 | 12: SDISR: DMA/interrupt status register | |
65 | 16: SFCR: FIFO control register | |
66 | 20: SBGR: baud rate control register | |
67 | 32: transfer FIFO buffer | |
68 | 48: transfer FIFO buffer | |
69 | ||
70 | backend {tcp | stdio} | |
71 | ||
72 | Use dv-sockser TCP-port backend or stdio for backend. Default: stdio. | |
73 | ||
74 | ||
75 | ||
76 | PORTS | |
77 | ||
78 | ||
79 | int (output) | |
80 | ||
81 | Interrupt port. An event is generated when a timer interrupt | |
82 | occurs. | |
83 | ||
84 | ||
85 | reset (input) | |
86 | ||
87 | Reset port. | |
88 | ||
89 | */ | |
90 | ||
91 | ||
92 | ||
93 | /* static functions */ | |
94 | ||
95 | struct tx3904sio_fifo; | |
96 | ||
97 | static void tx3904sio_tickle(struct hw*); | |
98 | static int tx3904sio_fifo_nonempty(struct hw*, struct tx3904sio_fifo*); | |
99 | static char tx3904sio_fifo_pop(struct hw*, struct tx3904sio_fifo*); | |
100 | static void tx3904sio_fifo_push(struct hw*, struct tx3904sio_fifo*, char); | |
101 | static void tx3904sio_fifo_reset(struct hw*, struct tx3904sio_fifo*); | |
102 | static void tx3904sio_poll(struct hw*, void* data); | |
103 | ||
104 | ||
105 | /* register numbers; each is one word long */ | |
d3eb0aa2 | 106 | enum |
c906108c SS |
107 | { |
108 | SLCR_REG = 0, | |
109 | SLSR_REG = 1, | |
110 | SDICR_REG = 2, | |
111 | SDISR_REG = 3, | |
112 | SFCR_REG = 4, | |
113 | SBGR_REG = 5, | |
114 | TFIFO_REG = 8, | |
115 | SFIFO_REG = 12, | |
116 | }; | |
117 | ||
118 | ||
119 | ||
120 | /* port ID's */ | |
121 | ||
122 | enum | |
123 | { | |
124 | RESET_PORT, | |
125 | INT_PORT, | |
126 | }; | |
127 | ||
128 | ||
d3eb0aa2 | 129 | static const struct hw_port_descriptor tx3904sio_ports[] = |
c906108c SS |
130 | { |
131 | { "int", INT_PORT, 0, output_port, }, | |
132 | { "reset", RESET_PORT, 0, input_port, }, | |
133 | { NULL, }, | |
134 | }; | |
135 | ||
136 | ||
137 | ||
138 | /* Generic FIFO */ | |
d3eb0aa2 | 139 | struct tx3904sio_fifo |
c906108c SS |
140 | { |
141 | int size, used; | |
142 | unsigned_1 *buffer; | |
143 | }; | |
144 | ||
145 | ||
146 | ||
147 | /* The timer/counter register internal state. Note that we store | |
148 | state using the control register images, in host endian order. */ | |
149 | ||
d3eb0aa2 | 150 | struct tx3904sio |
c906108c SS |
151 | { |
152 | address_word base_address; /* control register base */ | |
153 | enum {sio_tcp, sio_stdio} backend; /* backend */ | |
154 | ||
155 | struct tx3904sio_fifo rx_fifo, tx_fifo; /* FIFOs */ | |
156 | ||
157 | unsigned_4 slcr; | |
158 | #define SLCR_WR_MASK 0xe17f0000U | |
159 | #define SLCR_SET_BYTE(c,o,b) ((c)->slcr = SLCR_WR_MASK & (((c)->slcr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8))) | |
160 | unsigned_4 slsr; | |
161 | #define SLSR_WR_MASK 0x00000000 /* UFER/UPER/UOER unimplemented */ | |
162 | unsigned_4 sdicr; | |
163 | #define SDICR_WR_MASK 0x000f0000U | |
164 | #define SDICR_SET_BYTE(c,o,b) ((c)->sdicr = SDICR_WR_MASK & (((c)->sdicr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8))) | |
165 | #define SDICR_GET_SDMAE(c) ((c)->sdicr & 0x00080000) | |
166 | #define SDICR_GET_ERIE(c) ((c)->sdicr & 0x00040000) | |
167 | #define SDICR_GET_TDIE(c) ((c)->sdicr & 0x00020000) | |
168 | #define SDICR_GET_RDIE(c) ((c)->sdicr & 0x00010000) | |
169 | unsigned_4 sdisr; | |
170 | #define SDISR_WR_MASK 0x00070000U | |
171 | #define SDISR_SET_BYTE(c,o,b) ((c)->sdisr = SDISR_WR_MASK & (((c)->sdisr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8))) | |
c2d11a7d | 172 | #define SDISR_CLEAR_FLAG_BYTE(c,o,b) ((c)->sdisr = SDISR_WR_MASK & (((c)->sdisr & ~LSMASK32((o)*8+7,(o)*8)) & ((b)<< (o)*8))) |
c906108c SS |
173 | #define SDISR_GET_TDIS(c) ((c)->sdisr & 0x00020000) |
174 | #define SDISR_SET_TDIS(c) ((c)->sdisr |= 0x00020000) | |
175 | #define SDISR_GET_RDIS(c) ((c)->sdisr & 0x00010000) | |
176 | #define SDISR_SET_RDIS(c) ((c)->sdisr |= 0x00010000) | |
177 | unsigned_4 sfcr; | |
178 | #define SFCR_WR_MASK 0x001f0000U | |
179 | #define SFCR_SET_BYTE(c,o,b) ((c)->sfcr = SFCR_WR_MASK & (((c)->sfcr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8))) | |
180 | #define SFCR_GET_TFRST(c) ((c)->sfcr & 0x00040000) | |
181 | #define SFCR_GET_RFRST(c) ((c)->sfcr & 0x00020000) | |
182 | #define SFCR_GET_FRSTE(c) ((c)->sfcr & 0x00010000) | |
183 | unsigned_4 sbgr; | |
184 | #define SBGR_WR_MASK 0x03ff0000U | |
185 | #define SBGR_SET_BYTE(c,o,b) ((c)->sbgr = SBGR_WR_MASK & (((c)->sbgr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8))) | |
186 | ||
187 | /* Periodic I/O polling */ | |
188 | struct hw_event* poll_event; | |
189 | }; | |
190 | ||
191 | ||
192 | ||
193 | /* Finish off the partially created hw device. Attach our local | |
194 | callbacks. Wire up our port names etc */ | |
195 | ||
196 | static hw_io_read_buffer_method tx3904sio_io_read_buffer; | |
197 | static hw_io_write_buffer_method tx3904sio_io_write_buffer; | |
198 | static hw_port_event_method tx3904sio_port_event; | |
199 | ||
200 | ||
201 | static void | |
202 | attach_tx3904sio_regs (struct hw *me, | |
203 | struct tx3904sio *controller) | |
204 | { | |
205 | unsigned_word attach_address; | |
206 | int attach_space; | |
207 | unsigned attach_size; | |
208 | reg_property_spec reg; | |
209 | ||
210 | if (hw_find_property (me, "reg") == NULL) | |
211 | hw_abort (me, "Missing \"reg\" property"); | |
212 | ||
213 | if (!hw_find_reg_array_property (me, "reg", 0, ®)) | |
214 | hw_abort (me, "\"reg\" property must contain one addr/size entry"); | |
215 | ||
216 | hw_unit_address_to_attach_address (hw_parent (me), | |
217 | ®.address, | |
218 | &attach_space, | |
219 | &attach_address, | |
220 | me); | |
221 | hw_unit_size_to_attach_size (hw_parent (me), | |
222 | ®.size, | |
223 | &attach_size, me); | |
224 | ||
225 | hw_attach_address (hw_parent (me), 0, | |
226 | attach_space, attach_address, attach_size, | |
227 | me); | |
228 | ||
d3eb0aa2 | 229 | if (hw_find_property(me, "backend") != NULL) |
c906108c SS |
230 | { |
231 | const char* value = hw_find_string_property(me, "backend"); | |
d3eb0aa2 | 232 | if (!strcmp(value, "tcp")) |
c906108c | 233 | controller->backend = sio_tcp; |
d3eb0aa2 | 234 | else if (!strcmp(value, "stdio")) |
c906108c SS |
235 | controller->backend = sio_stdio; |
236 | else | |
237 | hw_abort(me, "illegal value for backend parameter `%s': use tcp or stdio", value); | |
238 | } | |
239 | ||
240 | controller->base_address = attach_address; | |
241 | } | |
242 | ||
243 | ||
244 | static void | |
245 | tx3904sio_finish (struct hw *me) | |
246 | { | |
247 | struct tx3904sio *controller; | |
248 | ||
249 | controller = HW_ZALLOC (me, struct tx3904sio); | |
250 | set_hw_data (me, controller); | |
251 | set_hw_io_read_buffer (me, tx3904sio_io_read_buffer); | |
252 | set_hw_io_write_buffer (me, tx3904sio_io_write_buffer); | |
253 | set_hw_ports (me, tx3904sio_ports); | |
254 | set_hw_port_event (me, tx3904sio_port_event); | |
255 | ||
256 | /* Preset defaults */ | |
257 | controller->backend = sio_stdio; | |
258 | ||
259 | /* Attach ourself to our parent bus */ | |
260 | attach_tx3904sio_regs (me, controller); | |
261 | ||
262 | /* Initialize to reset state */ | |
263 | tx3904sio_fifo_reset(me, & controller->rx_fifo); | |
264 | tx3904sio_fifo_reset(me, & controller->tx_fifo); | |
265 | controller->slsr = controller->sdicr | |
266 | = controller->sdisr = controller->sfcr | |
267 | = controller->sbgr = 0; | |
268 | controller->slcr = 0x40000000; /* set TWUB */ | |
269 | controller->sbgr = 0x03ff0000; /* set BCLK=3, BRD=FF */ | |
270 | controller->poll_event = NULL; | |
271 | } | |
272 | ||
273 | ||
274 | ||
275 | /* An event arrives on an interrupt port */ | |
276 | ||
277 | static void | |
278 | tx3904sio_port_event (struct hw *me, | |
279 | int my_port, | |
280 | struct hw *source, | |
281 | int source_port, | |
282 | int level) | |
283 | { | |
284 | struct tx3904sio *controller = hw_data (me); | |
285 | ||
286 | switch (my_port) | |
287 | { | |
288 | case RESET_PORT: | |
289 | { | |
290 | HW_TRACE ((me, "reset")); | |
291 | ||
292 | tx3904sio_fifo_reset(me, & controller->rx_fifo); | |
293 | tx3904sio_fifo_reset(me, & controller->tx_fifo); | |
294 | controller->slsr = controller->sdicr | |
295 | = controller->sdisr = controller->sfcr | |
296 | = controller->sbgr = 0; | |
297 | controller->slcr = 0x40000000; /* set TWUB */ | |
298 | controller->sbgr = 0x03ff0000; /* set BCLK=3, BRD=FF */ | |
299 | /* Don't interfere with I/O poller. */ | |
300 | break; | |
301 | } | |
302 | ||
303 | default: | |
304 | hw_abort (me, "Event on unknown port %d", my_port); | |
305 | break; | |
306 | } | |
307 | } | |
308 | ||
309 | ||
310 | /* generic read/write */ | |
311 | ||
312 | static unsigned | |
313 | tx3904sio_io_read_buffer (struct hw *me, | |
314 | void *dest, | |
315 | int space, | |
316 | unsigned_word base, | |
317 | unsigned nr_bytes) | |
318 | { | |
319 | struct tx3904sio *controller = hw_data (me); | |
320 | unsigned byte; | |
321 | ||
322 | HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes)); | |
323 | ||
324 | /* tickle fifos */ | |
325 | tx3904sio_tickle(me); | |
326 | ||
327 | for (byte = 0; byte < nr_bytes; byte++) | |
328 | { | |
329 | address_word address = base + byte; | |
330 | int reg_number = (address - controller->base_address) / 4; | |
331 | int reg_offset = (address - controller->base_address) % 4; | |
332 | unsigned_4 register_value; /* in target byte order */ | |
333 | ||
334 | /* fill in entire register_value word */ | |
335 | switch (reg_number) | |
336 | { | |
337 | case SLCR_REG: register_value = controller->slcr; break; | |
338 | case SLSR_REG: register_value = controller->slsr; break; | |
339 | case SDICR_REG: register_value = controller->sdicr; break; | |
340 | case SDISR_REG: register_value = controller->sdisr; break; | |
341 | case SFCR_REG: register_value = controller->sfcr; break; | |
342 | case SBGR_REG: register_value = controller->sbgr; break; | |
343 | case TFIFO_REG: register_value = 0; break; | |
344 | case SFIFO_REG: | |
345 | /* consume rx fifo for MS byte */ | |
d3eb0aa2 | 346 | if (reg_offset == 0 && tx3904sio_fifo_nonempty(me, & controller->rx_fifo)) |
c906108c SS |
347 | register_value = (tx3904sio_fifo_pop(me, & controller->rx_fifo) << 24); |
348 | else | |
349 | register_value = 0; | |
350 | break; | |
351 | default: register_value = 0; | |
352 | } | |
353 | ||
354 | /* write requested byte out */ | |
355 | register_value = H2T_4(register_value); | |
356 | /* HW_TRACE ((me, "byte %d %02x", reg_offset, ((char*)& register_value)[reg_offset])); */ | |
357 | memcpy ((char*) dest + byte, ((char*)& register_value)+reg_offset, 1); | |
358 | } | |
359 | ||
360 | return nr_bytes; | |
d3eb0aa2 | 361 | } |
c906108c SS |
362 | |
363 | ||
364 | ||
365 | static unsigned | |
366 | tx3904sio_io_write_buffer (struct hw *me, | |
367 | const void *source, | |
368 | int space, | |
369 | unsigned_word base, | |
370 | unsigned nr_bytes) | |
371 | { | |
372 | struct tx3904sio *controller = hw_data (me); | |
373 | unsigned byte; | |
374 | ||
375 | HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes)); | |
376 | for (byte = 0; byte < nr_bytes; byte++) | |
377 | { | |
378 | address_word address = base + byte; | |
379 | unsigned_1 write_byte = ((const unsigned char*) source)[byte]; | |
380 | int reg_number = (address - controller->base_address) / 4; | |
381 | int reg_offset = 3 - (address - controller->base_address) % 4; | |
382 | ||
383 | /* HW_TRACE ((me, "byte %d %02x", reg_offset, write_byte)); */ | |
384 | ||
385 | /* fill in entire register_value word */ | |
386 | switch (reg_number) | |
387 | { | |
388 | case SLCR_REG: | |
389 | SLCR_SET_BYTE(controller, reg_offset, write_byte); | |
390 | break; | |
391 | ||
392 | case SLSR_REG: /* unwriteable */ break; | |
393 | ||
394 | case SDICR_REG: | |
395 | { | |
396 | unsigned_4 last_int, next_int; | |
d3eb0aa2 | 397 | |
c906108c SS |
398 | /* deassert interrupt upon clear */ |
399 | last_int = controller->sdisr & controller->sdicr; | |
400 | /* HW_TRACE ((me, "sdicr - sdisr %08x sdicr %08x", | |
401 | controller->sdisr, controller->sdicr)); */ | |
402 | SDICR_SET_BYTE(controller, reg_offset, write_byte); | |
403 | /* HW_TRACE ((me, "sdicr + sdisr %08x sdicr %08x", | |
404 | controller->sdisr, controller->sdicr)); */ | |
405 | next_int = controller->sdisr & controller->sdicr; | |
d3eb0aa2 MF |
406 | |
407 | if (SDICR_GET_SDMAE(controller)) | |
c906108c SS |
408 | hw_abort(me, "Cannot support DMA-driven sio."); |
409 | ||
d3eb0aa2 | 410 | if (~last_int & next_int) /* any bits set? */ |
c906108c | 411 | hw_port_event(me, INT_PORT, 1); |
d3eb0aa2 | 412 | if (last_int & ~next_int) /* any bits cleared? */ |
c906108c SS |
413 | hw_port_event(me, INT_PORT, 0); |
414 | } | |
415 | break; | |
416 | ||
417 | case SDISR_REG: | |
418 | { | |
419 | unsigned_4 last_int, next_int; | |
420 | ||
421 | /* deassert interrupt upon clear */ | |
422 | last_int = controller->sdisr & controller->sdicr; | |
d3eb0aa2 | 423 | /* HW_TRACE ((me, "sdisr - sdisr %08x sdicr %08x", |
c906108c | 424 | controller->sdisr, controller->sdicr)); */ |
c2d11a7d | 425 | SDISR_CLEAR_FLAG_BYTE(controller, reg_offset, write_byte); |
d3eb0aa2 | 426 | /* HW_TRACE ((me, "sdisr + sdisr %08x sdicr %08x", |
c906108c SS |
427 | controller->sdisr, controller->sdicr)); */ |
428 | next_int = controller->sdisr & controller->sdicr; | |
429 | ||
d3eb0aa2 | 430 | if (~last_int & next_int) /* any bits set? */ |
c906108c | 431 | hw_port_event(me, INT_PORT, 1); |
d3eb0aa2 | 432 | if (last_int & ~next_int) /* any bits cleared? */ |
c906108c SS |
433 | hw_port_event(me, INT_PORT, 0); |
434 | } | |
435 | break; | |
d3eb0aa2 | 436 | |
c906108c SS |
437 | case SFCR_REG: |
438 | SFCR_SET_BYTE(controller, reg_offset, write_byte); | |
d3eb0aa2 | 439 | if (SFCR_GET_FRSTE(controller)) |
c906108c | 440 | { |
d3eb0aa2 MF |
441 | if (SFCR_GET_TFRST(controller)) tx3904sio_fifo_reset(me, & controller->tx_fifo); |
442 | if (SFCR_GET_RFRST(controller)) tx3904sio_fifo_reset(me, & controller->rx_fifo); | |
c906108c SS |
443 | } |
444 | break; | |
d3eb0aa2 | 445 | |
c906108c SS |
446 | case SBGR_REG: |
447 | SBGR_SET_BYTE(controller, reg_offset, write_byte); | |
448 | break; | |
d3eb0aa2 | 449 | |
c906108c | 450 | case SFIFO_REG: /* unwriteable */ break; |
d3eb0aa2 MF |
451 | |
452 | case TFIFO_REG: | |
453 | if (reg_offset == 3) /* first byte */ | |
c906108c SS |
454 | tx3904sio_fifo_push(me, & controller->tx_fifo, write_byte); |
455 | break; | |
456 | ||
d3eb0aa2 | 457 | default: |
c906108c SS |
458 | HW_TRACE ((me, "write to illegal register %d", reg_number)); |
459 | } | |
460 | } /* loop over bytes */ | |
461 | ||
462 | /* tickle fifos */ | |
463 | tx3904sio_tickle(me); | |
464 | ||
465 | return nr_bytes; | |
d3eb0aa2 | 466 | } |
c906108c SS |
467 | |
468 | ||
469 | ||
470 | ||
471 | ||
472 | ||
473 | /* Send enqueued characters from tx_fifo and trigger TX interrupt. | |
474 | Receive characters into rx_fifo and trigger RX interrupt. */ | |
475 | void | |
476 | tx3904sio_tickle(struct hw *me) | |
477 | { | |
478 | struct tx3904sio* controller = hw_data(me); | |
479 | int c; | |
480 | char cc; | |
481 | unsigned_4 last_int, next_int; | |
482 | ||
483 | /* HW_TRACE ((me, "tickle backend: %02x", controller->backend)); */ | |
d3eb0aa2 | 484 | switch (controller->backend) |
c906108c SS |
485 | { |
486 | case sio_tcp: | |
487 | ||
488 | while(tx3904sio_fifo_nonempty(me, & controller->tx_fifo)) | |
489 | { | |
490 | cc = tx3904sio_fifo_pop(me, & controller->tx_fifo); | |
491 | dv_sockser_write(hw_system(me), cc); | |
492 | HW_TRACE ((me, "tcp output: %02x", cc)); | |
493 | } | |
494 | ||
495 | c = dv_sockser_read(hw_system(me)); | |
496 | while(c != -1) | |
497 | { | |
498 | cc = (char) c; | |
499 | HW_TRACE ((me, "tcp input: %02x", cc)); | |
500 | tx3904sio_fifo_push(me, & controller->rx_fifo, cc); | |
501 | c = dv_sockser_read(hw_system(me)); | |
502 | } | |
503 | break; | |
504 | ||
505 | case sio_stdio: | |
506 | ||
507 | while(tx3904sio_fifo_nonempty(me, & controller->tx_fifo)) | |
508 | { | |
509 | cc = tx3904sio_fifo_pop(me, & controller->tx_fifo); | |
510 | sim_io_write_stdout(hw_system(me), & cc, 1); | |
511 | sim_io_flush_stdout(hw_system(me)); | |
512 | HW_TRACE ((me, "stdio output: %02x", cc)); | |
513 | } | |
514 | ||
515 | c = sim_io_poll_read(hw_system(me), 0 /* stdin */, & cc, 1); | |
516 | while(c == 1) | |
517 | { | |
518 | HW_TRACE ((me, "stdio input: %02x", cc)); | |
519 | tx3904sio_fifo_push(me, & controller->rx_fifo, cc); | |
520 | c = sim_io_poll_read(hw_system(me), 0 /* stdin */, & cc, 1); | |
521 | } | |
522 | ||
523 | break; | |
524 | ||
525 | default: | |
526 | hw_abort(me, "Illegal backend mode: %d", controller->backend); | |
527 | } | |
528 | ||
529 | /* Update RDIS / TDIS flags */ | |
530 | last_int = controller->sdisr & controller->sdicr; | |
531 | /* HW_TRACE ((me, "tickle - sdisr %08x sdicr %08x", controller->sdisr, controller->sdicr)); */ | |
d3eb0aa2 | 532 | if (tx3904sio_fifo_nonempty(me, & controller->rx_fifo)) |
c906108c | 533 | SDISR_SET_RDIS(controller); |
d3eb0aa2 | 534 | if (!tx3904sio_fifo_nonempty(me, & controller->tx_fifo)) |
c906108c SS |
535 | SDISR_SET_TDIS(controller); |
536 | next_int = controller->sdisr & controller->sdicr; | |
537 | /* HW_TRACE ((me, "tickle + sdisr %08x sdicr %08x", controller->sdisr, controller->sdicr)); */ | |
538 | ||
d3eb0aa2 | 539 | if (~last_int & next_int) /* any bits set? */ |
c906108c | 540 | hw_port_event(me, INT_PORT, 1); |
d3eb0aa2 | 541 | if (last_int & ~next_int) /* any bits cleared? */ |
c906108c SS |
542 | hw_port_event(me, INT_PORT, 0); |
543 | ||
544 | /* Add periodic polling for this port, if it's not already going. */ | |
d3eb0aa2 | 545 | if (controller->poll_event == NULL) |
c906108c SS |
546 | { |
547 | controller->poll_event = hw_event_queue_schedule (me, 1000, | |
548 | tx3904sio_poll, NULL); | |
549 | ||
550 | } | |
551 | } | |
552 | ||
553 | ||
554 | ||
555 | ||
556 | int | |
557 | tx3904sio_fifo_nonempty(struct hw* me, struct tx3904sio_fifo* fifo) | |
558 | { | |
559 | /* HW_TRACE ((me, "fifo used: %d", fifo->used)); */ | |
560 | return(fifo->used > 0); | |
561 | } | |
562 | ||
563 | ||
564 | char | |
565 | tx3904sio_fifo_pop(struct hw* me, struct tx3904sio_fifo* fifo) | |
566 | { | |
567 | char it; | |
568 | ASSERT(fifo->used > 0); | |
569 | ASSERT(fifo->buffer != NULL); | |
570 | it = fifo->buffer[0]; | |
571 | memcpy(& fifo->buffer[0], & fifo->buffer[1], fifo->used - 1); | |
572 | fifo->used --; | |
573 | /* HW_TRACE ((me, "pop fifo -> %02x", it)); */ | |
574 | return it; | |
575 | } | |
576 | ||
577 | ||
578 | void | |
579 | tx3904sio_fifo_push(struct hw* me, struct tx3904sio_fifo* fifo, char it) | |
580 | { | |
581 | /* HW_TRACE ((me, "push %02x -> fifo", it)); */ | |
d3eb0aa2 | 582 | if (fifo->size == fifo->used) /* full */ |
c906108c SS |
583 | { |
584 | int next_size = fifo->size * 2 + 16; | |
df32b446 | 585 | unsigned_1* next_buf = zalloc(next_size); |
c906108c SS |
586 | memcpy(next_buf, fifo->buffer, fifo->used); |
587 | ||
d3eb0aa2 | 588 | if (fifo->buffer != NULL) free(fifo->buffer); |
c906108c SS |
589 | fifo->buffer = next_buf; |
590 | fifo->size = next_size; | |
591 | } | |
592 | ||
593 | fifo->buffer[fifo->used] = it; | |
594 | fifo->used ++; | |
595 | } | |
596 | ||
597 | ||
598 | void | |
599 | tx3904sio_fifo_reset(struct hw* me, struct tx3904sio_fifo* fifo) | |
600 | { | |
601 | /* HW_TRACE ((me, "reset fifo")); */ | |
602 | fifo->used = 0; | |
603 | fifo->size = 0; | |
d79fe0d6 | 604 | free(fifo->buffer); |
c906108c SS |
605 | fifo->buffer = 0; |
606 | } | |
607 | ||
608 | ||
609 | void | |
610 | tx3904sio_poll(struct hw* me, void* ignored) | |
611 | { | |
612 | struct tx3904sio* controller = hw_data (me); | |
613 | tx3904sio_tickle (me); | |
614 | hw_event_queue_deschedule (me, controller->poll_event); | |
615 | controller->poll_event = hw_event_queue_schedule (me, 1000, | |
616 | tx3904sio_poll, NULL); | |
617 | } | |
618 | ||
619 | ||
620 | ||
621 | const struct hw_descriptor dv_tx3904sio_descriptor[] = { | |
622 | { "tx3904sio", tx3904sio_finish, }, | |
623 | { NULL }, | |
624 | }; |