fix potens not being set in ttyFB* device
[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/owloysius.h>
5 #include <lunaix/status.h>
6 #include <lunaix/syslog.h>
7
8 #include <asm/pagetable.h>
9
10 #include <hal/serial.h>
11
12 LOG_MODULE("serial")
13
14 #define lock_sdev(sdev) device_lock((sdev)->dev)
15 #define unlock_sdev(sdev) device_unlock((sdev)->dev)
16 #define unlock_and_wait(sdev, wq)                                              \
17     ({                                                                         \
18         unlock_sdev(sdev);                                                     \
19         pwait(&(sdev)->wq);                                                    \
20         lock_sdev(sdev);                                                       \
21     })
22
23 static DEFINE_LLIST(serial_devs);
24 static int serial_idx = 0;
25
26 static struct device_cat* serial_cat;
27
28 #define serial_device(dev) ((struct serial_dev*)(dev)->underlay)
29
30 int
31 serial_accept_one(struct serial_dev* sdev, u8_t val)
32 {
33     return !!rbuffer_put(&sdev->rxbuf, val);
34 }
35
36 int
37 serial_accept_buffer(struct serial_dev* sdev, void* val, size_t len)
38 {
39     return !!rbuffer_puts(&sdev->rxbuf, val, len);
40 }
41
42 void
43 serial_end_recv(struct serial_dev* sdev)
44 {
45     mark_device_done_read(sdev->dev);
46
47     pwake_one(&sdev->wq_rxdone);
48
49     term_notify_data_avaliable(sdev->tp_cap);
50 }
51
52 void
53 serial_end_xmit(struct serial_dev* sdev, size_t len)
54 {
55     mark_device_done_write(sdev->dev);
56
57     sdev->wr_len = len;
58     pwake_one(&sdev->wq_txdone);
59 }
60
61 int
62 serial_readone_nowait(struct serial_dev* sdev, u8_t* val)
63 {
64     lock_sdev(sdev);
65
66     int rd_len = rbuffer_get(&sdev->rxbuf, (char*)val);
67
68     unlock_sdev(sdev);
69
70     return rd_len;
71 }
72
73 void
74 serial_readone(struct serial_dev* sdev, u8_t* val)
75 {
76     lock_sdev(sdev);
77
78     mark_device_doing_read(sdev->dev);
79
80     while (!rbuffer_get(&sdev->rxbuf, (char*)val)) {
81         unlock_and_wait(sdev, wq_rxdone);
82     }
83
84     unlock_sdev(sdev);
85 }
86
87 size_t
88 serial_readbuf(struct serial_dev* sdev, u8_t* buf, size_t len)
89 {
90     lock_sdev(sdev);
91
92     mark_device_doing_read(sdev->dev);
93
94     size_t rdlen;
95     while (!(rdlen = rbuffer_gets(&sdev->rxbuf, (char*)buf, len))) {
96         unlock_and_wait(sdev, wq_rxdone);
97     }
98
99     unlock_sdev(sdev);
100
101     return rdlen;
102 }
103
104 int
105 serial_readbuf_nowait(struct serial_dev* sdev, u8_t* buf, size_t len)
106 {
107     lock_sdev(sdev);
108
109     mark_device_doing_read(sdev->dev);
110
111     int rdlen = rbuffer_gets(&sdev->rxbuf, (char*)buf, len);
112
113     unlock_sdev(sdev);
114
115     return rdlen;
116 }
117
118 int
119 serial_writebuf(struct serial_dev* sdev, u8_t* buf, size_t len)
120 {
121     lock_sdev(sdev);
122
123     mark_device_doing_write(sdev->dev);
124
125     if (sdev->write(sdev, buf, len) == RXTX_DONE) {
126         goto done;
127     }
128
129     unlock_and_wait(sdev, wq_txdone);
130
131 done:
132     int rdlen = sdev->wr_len;
133     unlock_sdev(sdev);
134
135     return rdlen;
136 }
137
138 int
139 serial_writebuf_nowait(struct serial_dev* sdev, u8_t* buf, size_t len)
140 {
141     lock_sdev(sdev);
142
143     mark_device_doing_write(sdev->dev);
144
145     sdev->write(sdev, buf, len);
146     int rdlen = sdev->wr_len;
147
148     unlock_sdev(sdev);
149
150     return rdlen;
151 }
152
153 static int
154 __serial_read(struct device* dev, void* buf, off_t fpos, size_t len)
155 {
156     return serial_readbuf(serial_device(dev), (u8_t*)buf, len);
157 }
158
159 static int
160 __serial_read_async(struct device* dev, void* buf, off_t fpos, size_t len)
161 {
162     return serial_readbuf_nowait(
163         serial_device(dev), (u8_t*)buf, len);
164 }
165
166 static int
167 __serial_read_page(struct device* dev, void* buf, off_t fpos)
168 {
169     return serial_readbuf(serial_device(dev), (u8_t*)buf, PAGE_SIZE);
170 }
171
172 static int
173 __serial_write(struct device* dev, void* buf, off_t fpos, size_t len)
174 {
175     return serial_writebuf(serial_device(dev), (u8_t*)buf, len);
176 }
177
178 static int
179 __serial_write_async(struct device* dev, void* buf, off_t fpos, size_t len)
180 {
181     return serial_writebuf_nowait(
182         serial_device(dev), (u8_t*)buf, len);
183 }
184
185 static int
186 __serial_write_page(struct device* dev, void* buf, off_t fpos)
187 {
188     return serial_writebuf(serial_device(dev), (u8_t*)buf, PAGE_SIZE);
189 }
190
191 static int
192 __serial_exec_command(struct device* dev, u32_t req, va_list args)
193 {
194     struct serial_dev* sdev = serial_device(dev);
195
196     if (!sdev->exec_cmd) {
197         return ENOTSUP;
198     }
199
200     return sdev->exec_cmd(sdev, req, args);
201 }
202
203 static int
204 __serial_poll_event(struct device* dev)
205 {
206     struct serial_dev* sdev = serial_device(dev);
207
208     return sdev->dev->poll_evflags;
209 }
210
211 static void sdev_execmd(struct serial_dev* sdev, u32_t req, ...)
212 {
213     va_list args;
214     va_start(args, req);
215
216     sdev->exec_cmd(sdev, req, args);
217
218     va_end(args);
219 }
220
221 static void
222 __serial_set_speed(struct device* dev, speed_t speed)
223 {
224     struct serial_dev* sdev = serial_device(dev);
225     lock_sdev(sdev);
226
227     sdev_execmd(sdev, SERIO_SETBRDRATE, speed);
228
229     unlock_sdev(sdev);
230 }
231
232 static void
233 __serial_set_baseclk(struct device* dev, unsigned int base)
234 {
235     struct serial_dev* sdev = serial_device(dev);
236     lock_sdev(sdev);
237
238     sdev_execmd(sdev, SERIO_SETBRDBASE, base);
239
240     unlock_sdev(sdev);
241 }
242
243 static void
244 __serial_set_cntrl_mode(struct device* dev, tcflag_t cflag)
245 {
246     struct serial_dev* sdev = serial_device(dev);
247     lock_sdev(sdev);
248
249     sdev_execmd(sdev, SERIO_SETCNTRLMODE, cflag);
250
251     unlock_sdev(sdev);
252 }
253
254 #define RXBUF_SIZE 512
255
256 static struct termport_pot_ops tppot_ops = {
257     .set_cntrl_mode = __serial_set_cntrl_mode,
258     .set_clkbase = __serial_set_baseclk,
259     .set_speed = __serial_set_speed
260 };
261
262 struct serial_dev*
263 serial_create(struct devclass* class, char* if_ident)
264 {
265     struct serial_dev* sdev;
266     struct device* dev;
267     
268     sdev = vzalloc(sizeof(struct serial_dev));
269     dev = device_allocseq(dev_meta(serial_cat), sdev);
270
271     dev->ops.read = __serial_read;
272     dev->ops.read_page = __serial_read_page;
273     dev->ops.read_async = __serial_read_async;
274     dev->ops.write_async = __serial_write_async;
275     dev->ops.write = __serial_write;
276     dev->ops.write_page = __serial_write_page;
277     dev->ops.exec_cmd = __serial_exec_command;
278     dev->ops.poll = __serial_poll_event;
279     
280     sdev->dev = dev;
281     dev->underlay = sdev;
282
283     waitq_init(&sdev->wq_rxdone);
284     waitq_init(&sdev->wq_txdone);
285     rbuffer_init(&sdev->rxbuf, valloc(RXBUF_SIZE), RXBUF_SIZE);
286     llist_append(&serial_devs, &sdev->sdev_list);
287     
288     register_device_var(dev, class, "%s", if_ident);
289
290     INFO("interface: %s, %xh:%xh.%d", dev->name_val, 
291             class->fn_grp, class->device, class->variant);
292
293     sdev->tp_cap = term_attach_potens(dev, &tppot_ops, if_ident);
294
295     return sdev;
296 }
297
298 struct serial_dev*
299 serial_get_avilable()
300 {
301     struct serial_dev *pos, *n;
302     llist_for_each(pos, n, &serial_devs, sdev_list)
303     {
304         if (!device_locked(pos->dev)) {
305             return pos;
306         }
307     }
308
309     return NULL;
310 }
311
312 static void
313 init_serial_dev()
314 {
315     serial_cat = device_addcat(NULL, "serial");
316
317     assert(serial_cat);
318 }
319 owloysius_fetch_init(init_serial_dev, on_earlyboot)