feat: standard vga support (mode switching, framebuffer remapping)
[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 !!fifo_putone(&sdev->rxbuf, val);
19 }
20
21 int
22 serial_accept_buffer(struct serial_dev* sdev, void* val, size_t len)
23 {
24     return !!fifo_write(&sdev->rxbuf, val, len);
25 }
26
27 void
28 serial_end_recv(struct serial_dev* sdev)
29 {
30     pwake_one(&sdev->wq_rxdone);
31 }
32
33 void
34 serial_end_xmit(struct serial_dev* sdev, size_t len)
35 {
36     sdev->wr_len = len;
37     pwake_one(&sdev->wq_txdone);
38 }
39
40 int
41 serial_readone_nowait(struct serial_dev* sdev, u8_t* val)
42 {
43     device_lock(sdev->dev);
44
45     int rd_len = fifo_readone(&sdev->rxbuf, val);
46
47     device_unlock(sdev->dev);
48
49     return rd_len;
50 }
51
52 void
53 serial_readone(struct serial_dev* sdev, u8_t* val)
54 {
55     device_lock(sdev->dev);
56
57     while (!fifo_readone(&sdev->rxbuf, val)) {
58         pwait(&sdev->wq_rxdone);
59     }
60
61     device_unlock(sdev->dev);
62 }
63
64 size_t
65 serial_readbuf(struct serial_dev* sdev, u8_t* buf, size_t len)
66 {
67     device_lock(sdev->dev);
68
69     size_t rdlen;
70     while (!(rdlen = fifo_read(&sdev->rxbuf, buf, len))) {
71         pwait(&sdev->wq_rxdone);
72     }
73
74     device_unlock(sdev->dev);
75
76     return rdlen;
77 }
78
79 int
80 serial_readbuf_nowait(struct serial_dev* sdev, u8_t* buf, size_t len)
81 {
82     device_lock(sdev->dev);
83
84     int rdlen = fifo_read(&sdev->rxbuf, buf, len);
85
86     device_unlock(sdev->dev);
87
88     return rdlen;
89 }
90
91 int
92 serial_writebuf(struct serial_dev* sdev, u8_t* buf, size_t len)
93 {
94     device_lock(sdev->dev);
95
96     if (sdev->write(sdev, buf, len) == RXTX_DONE) {
97         goto done;
98     }
99
100     pwait(&sdev->wq_txdone);
101
102 done:
103     int rdlen = sdev->wr_len;
104     device_unlock(sdev->dev);
105
106     return rdlen;
107 }
108
109 int
110 serial_writebuf_nowait(struct serial_dev* sdev, u8_t* buf, size_t len)
111 {
112     device_lock(sdev->dev);
113
114     sdev->write(sdev, buf, len);
115     int rdlen = sdev->wr_len;
116
117     device_unlock(sdev->dev);
118
119     return rdlen;
120 }
121
122 static int
123 __serial_read(struct device* dev, void* buf, size_t offset, size_t len)
124 {
125     return serial_readbuf(serial_device(dev), &((u8_t*)buf)[offset], len);
126 }
127
128 static int
129 __serial_read_page(struct device* dev, void* buf, size_t offset)
130 {
131     return serial_readbuf(serial_device(dev), &((u8_t*)buf)[offset], MEM_PAGE);
132 }
133
134 static int
135 __serial_write(struct device* dev, void* buf, size_t offset, size_t len)
136 {
137     return serial_writebuf(serial_device(dev), &((u8_t*)buf)[offset], len);
138 }
139
140 static int
141 __serial_write_page(struct device* dev, void* buf, size_t offset)
142 {
143     return serial_writebuf(serial_device(dev), &((u8_t*)buf)[offset], MEM_PAGE);
144 }
145
146 static int
147 __serial_exec_command(struct device* dev, u32_t req, va_list args)
148 {
149     struct serial_dev* sdev = serial_device(dev);
150
151     if (!sdev->exec_cmd) {
152         return ENOTSUP;
153     }
154
155     return sdev->exec_cmd(sdev, req, args);
156 }
157
158 #define RXBUF_SIZE 512
159
160 struct serial_dev*
161 serial_create(struct devclass* class)
162 {
163     struct serial_dev* sdev = valloc(sizeof(struct serial_dev));
164     struct device* dev = device_allocseq(NULL, sdev);
165     dev->ops.read = __serial_read;
166     dev->ops.read_page = __serial_read_page;
167     dev->ops.write = __serial_write;
168     dev->ops.write_page = __serial_write_page;
169     dev->ops.exec_cmd = __serial_exec_command;
170
171     sdev->dev = dev;
172     dev->underlay = sdev;
173
174     waitq_init(&sdev->wq_rxdone);
175     waitq_init(&sdev->wq_txdone);
176     fifo_init(&sdev->rxbuf, valloc(RXBUF_SIZE), RXBUF_SIZE, 0);
177     llist_append(&serial_devs, &sdev->sdev_list);
178     // llist_init_head(&sdev->cmds);
179
180     class->variant++;
181     device_register(dev, class, "ttyS%d", class->variant);
182
183     return sdev;
184 }
185
186 struct serial_dev*
187 serial_get_avilable()
188 {
189     struct serial_dev *pos, *n;
190     llist_for_each(pos, n, &serial_devs, sdev_list)
191     {
192         if (!device_locked(pos->dev)) {
193             return pos;
194         }
195     }
196
197     return NULL;
198 }