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