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