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