feat: owloysius - dynamic init function invocator
[lunaix-os.git] / lunaix-os / hal / char / serial.c
1 #include <lunaix/device.h>
2 #include <lunaix/mm/valloc.h>
3 #include <lunaix/spike.h>
4 #include <lunaix/status.h>
5
6 #include <sys/mm/mempart.h>
7
8 #include <hal/serial.h>
9
10 #define lock_sdev(sdev) device_lock((sdev)->dev)
11 #define unlock_sdev(sdev) device_unlock((sdev)->dev)
12 #define unlock_and_wait(sdev, wq)                                              \
13     ({                                                                         \
14         unlock_sdev(sdev);                                                     \
15         pwait(&(sdev)->wq);                                                    \
16         lock_sdev(sdev);                                                       \
17     })
18
19 static DEFINE_LLIST(serial_devs);
20 static int serial_idx = 0;
21
22 #define serial_device(dev) ((struct serial_dev*)(dev)->underlay)
23
24 int
25 serial_accept_one(struct serial_dev* sdev, u8_t val)
26 {
27     return !!rbuffer_put(&sdev->rxbuf, val);
28 }
29
30 int
31 serial_accept_buffer(struct serial_dev* sdev, void* val, size_t len)
32 {
33     return !!rbuffer_puts(&sdev->rxbuf, val, len);
34 }
35
36 void
37 serial_end_recv(struct serial_dev* sdev)
38 {
39     mark_device_done_read(sdev->dev);
40
41     pwake_one(&sdev->wq_rxdone);
42 }
43
44 void
45 serial_end_xmit(struct serial_dev* sdev, size_t len)
46 {
47     mark_device_done_write(sdev->dev);
48
49     sdev->wr_len = len;
50     pwake_one(&sdev->wq_txdone);
51 }
52
53 int
54 serial_readone_nowait(struct serial_dev* sdev, u8_t* val)
55 {
56     lock_sdev(sdev);
57
58     int rd_len = rbuffer_get(&sdev->rxbuf, (char*)val);
59
60     unlock_sdev(sdev);
61
62     return rd_len;
63 }
64
65 void
66 serial_readone(struct serial_dev* sdev, u8_t* val)
67 {
68     lock_sdev(sdev);
69
70     mark_device_doing_read(sdev->dev);
71
72     while (!rbuffer_get(&sdev->rxbuf, (char*)val)) {
73         unlock_and_wait(sdev, wq_rxdone);
74     }
75
76     unlock_sdev(sdev);
77 }
78
79 size_t
80 serial_readbuf(struct serial_dev* sdev, u8_t* buf, size_t len)
81 {
82     lock_sdev(sdev);
83
84     mark_device_doing_read(sdev->dev);
85
86     size_t rdlen;
87     while (!(rdlen = rbuffer_gets(&sdev->rxbuf, (char*)buf, len))) {
88         unlock_and_wait(sdev, wq_rxdone);
89     }
90
91     unlock_sdev(sdev);
92
93     return rdlen;
94 }
95
96 int
97 serial_readbuf_nowait(struct serial_dev* sdev, u8_t* buf, size_t len)
98 {
99     lock_sdev(sdev);
100
101     mark_device_doing_read(sdev->dev);
102
103     int rdlen = rbuffer_gets(&sdev->rxbuf, (char*)buf, len);
104
105     unlock_sdev(sdev);
106
107     return rdlen;
108 }
109
110 int
111 serial_writebuf(struct serial_dev* sdev, u8_t* buf, size_t len)
112 {
113     lock_sdev(sdev);
114
115     mark_device_doing_write(sdev->dev);
116
117     if (sdev->write(sdev, buf, len) == RXTX_DONE) {
118         goto done;
119     }
120
121     unlock_and_wait(sdev, wq_txdone);
122
123 done:
124     int rdlen = sdev->wr_len;
125     unlock_sdev(sdev);
126
127     return rdlen;
128 }
129
130 int
131 serial_writebuf_nowait(struct serial_dev* sdev, u8_t* buf, size_t len)
132 {
133     lock_sdev(sdev);
134
135     mark_device_doing_write(sdev->dev);
136
137     sdev->write(sdev, buf, len);
138     int rdlen = sdev->wr_len;
139
140     unlock_sdev(sdev);
141
142     return rdlen;
143 }
144
145 static int
146 __serial_read(struct device* dev, void* buf, size_t offset, size_t len)
147 {
148     return serial_readbuf(serial_device(dev), &((u8_t*)buf)[offset], len);
149 }
150
151 static int
152 __serial_read_async(struct device* dev, void* buf, size_t offset, size_t len)
153 {
154     return serial_readbuf_nowait(
155         serial_device(dev), &((u8_t*)buf)[offset], len);
156 }
157
158 static int
159 __serial_read_page(struct device* dev, void* buf, size_t offset)
160 {
161     return serial_readbuf(serial_device(dev), &((u8_t*)buf)[offset], MEM_PAGE);
162 }
163
164 static int
165 __serial_write(struct device* dev, void* buf, size_t offset, size_t len)
166 {
167     return serial_writebuf(serial_device(dev), &((u8_t*)buf)[offset], len);
168 }
169
170 static int
171 __serial_write_async(struct device* dev, void* buf, size_t offset, size_t len)
172 {
173     return serial_writebuf_nowait(
174         serial_device(dev), &((u8_t*)buf)[offset], len);
175 }
176
177 static int
178 __serial_write_page(struct device* dev, void* buf, size_t offset)
179 {
180     return serial_writebuf(serial_device(dev), &((u8_t*)buf)[offset], MEM_PAGE);
181 }
182
183 static int
184 __serial_exec_command(struct device* dev, u32_t req, va_list args)
185 {
186     struct serial_dev* sdev = serial_device(dev);
187
188     if (!sdev->exec_cmd) {
189         return ENOTSUP;
190     }
191
192     return sdev->exec_cmd(sdev, req, args);
193 }
194
195 static int
196 __serial_poll_event(struct device* dev)
197 {
198     struct serial_dev* sdev = serial_device(dev);
199
200     return sdev->dev->poll_evflags;
201 }
202
203 #define RXBUF_SIZE 512
204
205 struct serial_dev*
206 serial_create(struct devclass* class, char* if_ident)
207 {
208     struct serial_dev* sdev = valloc(sizeof(struct serial_dev));
209     struct device* dev = device_allocseq(NULL, sdev);
210     dev->ops.read = __serial_read;
211     dev->ops.read_page = __serial_read_page;
212     dev->ops.read_async = __serial_read_async;
213     dev->ops.write_async = __serial_write_async;
214     dev->ops.write = __serial_write;
215     dev->ops.write_page = __serial_write_page;
216     dev->ops.exec_cmd = __serial_exec_command;
217     dev->ops.poll = __serial_poll_event;
218
219     sdev->dev = dev;
220     dev->underlay = sdev;
221
222     waitq_init(&sdev->wq_rxdone);
223     waitq_init(&sdev->wq_txdone);
224     rbuffer_init(&sdev->rxbuf, valloc(RXBUF_SIZE), RXBUF_SIZE);
225     llist_append(&serial_devs, &sdev->sdev_list);
226
227     register_device(dev, class, "port%s%d", if_ident, class->variant);
228
229     sdev->at_term = term_create(dev, if_ident);
230
231     class->variant++;
232     return sdev;
233 }
234
235 struct serial_dev*
236 serial_get_avilable()
237 {
238     struct serial_dev *pos, *n;
239     llist_for_each(pos, n, &serial_devs, sdev_list)
240     {
241         if (!device_locked(pos->dev)) {
242             return pos;
243         }
244     }
245
246     return NULL;
247 }