avr_register_io_[read,write](): fail if overriding earlier registration.
[simavr] / simavr / sim / sim_io.c
1 /*
2         sim_io.c
3
4         Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
5
6         This file is part of simavr.
7
8         simavr is free software: you can redistribute it and/or modify
9         it under the terms of the GNU General Public License as published by
10         the Free Software Foundation, either version 3 of the License, or
11         (at your option) any later version.
12
13         simavr is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17
18         You should have received a copy of the GNU General Public License
19         along with simavr.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include "sim_io.h"
27
28 int avr_ioctl(avr_t *avr, uint32_t ctl, void * io_param)
29 {
30         avr_io_t * port = avr->io_port;
31         int res = -1;
32         while (port && res == -1) {
33                 if (port->ioctl)
34                         res = port->ioctl(port, ctl, io_param);
35                 port = port->next;
36         }
37         return res;
38 }
39
40 void avr_register_io(avr_t *avr, avr_io_t * io)
41 {
42         io->next = avr->io_port;
43         io->avr = avr;
44         avr->io_port = io;
45 }
46
47 void avr_register_io_read(avr_t *avr, avr_io_addr_t addr, avr_io_read_t readp, void * param)
48 {
49         avr_io_addr_t a = AVR_DATA_TO_IO(addr);
50         if (avr->io[a].r.param || avr->io[a].r.c) {
51                 fputs("Error: avr_register_io_read(): Already registered, refusing to override.\n", stderr);
52                 exit(1);
53         }
54         avr->io[a].r.param = param;
55         avr->io[a].r.c = readp;
56 }
57
58 void avr_register_io_write(avr_t *avr, avr_io_addr_t addr, avr_io_write_t writep, void * param)
59 {
60         avr_io_addr_t a = AVR_DATA_TO_IO(addr);
61         if (avr->io[a].w.param || avr->io[a].w.c) {
62                 fputs("Error: avr_register_io_write(): Already registered, refusing to override.\n", stderr);
63                 exit(1);
64         }
65         avr->io[a].w.param = param;
66         avr->io[a].w.c = writep;
67 }
68
69 struct avr_irq_t * avr_io_getirq(avr_t * avr, uint32_t ctl, int index)
70 {
71         avr_io_t * port = avr->io_port;
72         while (port) {
73                 if (port->irq && port->irq_ioctl_get == ctl && port->irq_count > index)
74                         return port->irq + index;
75                 port = port->next;
76         }
77         return NULL;
78         
79 }
80
81 avr_irq_t * avr_iomem_getirq(avr_t * avr, avr_io_addr_t addr, int index)
82 {
83         avr_io_addr_t a = AVR_DATA_TO_IO(addr);
84         if (avr->io[a].irq == NULL) {
85                 avr->io[a].irq = avr_alloc_irq(0, 9);
86                 // mark the pin ones as filtered, so they only are raised when changing
87                 for (int i = 0; i < 8; i++)
88                         avr->io[a].irq[i].flags |= IRQ_FLAG_FILTERED;
89         }
90         return index < 9 ? avr->io[a].irq + index : NULL;
91 }
92
93 struct avr_irq_t * avr_io_setirqs(avr_io_t * io, uint32_t ctl, int count, struct avr_irq_t * irqs)
94 {
95         // allocate this module's IRQ
96         io->irq_count = count;
97         io->irq = irqs ? irqs : avr_alloc_irq(0, count);
98         io->irq_ioctl_get = ctl;
99         return io->irq;
100 }
101
102 static void avr_deallocate_io(avr_io_t * io)
103 {
104         if (io->dealloc)
105                 io->dealloc(io);
106         avr_free_irq(io->irq, io->irq_count);
107         io->irq_count = 0;
108         io->irq_ioctl_get = 0;
109         io->avr = NULL;
110         io->next = NULL;
111 }
112
113 void avr_deallocate_ios(avr_t * avr)
114 {
115         avr_io_t * port = avr->io_port;
116         while (port) {
117                 avr_io_t * next = port->next;
118                 avr_deallocate_io(port);
119                 port = next;
120         }
121         avr->io_port = NULL;
122 }