regression: test serial port r/w.
[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     mutex_lock(&sdev->lock);
44
45     int rd_len = fifo_readone(&sdev->rxbuf, val);
46
47     mutex_unlock(&sdev->lock);
48
49     return rd_len;
50 }
51
52 void
53 serial_readone(struct serial_dev* sdev, u8_t* val)
54 {
55     mutex_lock(&sdev->lock);
56
57     while (!fifo_readone(&sdev->rxbuf, val)) {
58         pwait(&sdev->wq_rxdone);
59     }
60
61     mutex_unlock(&sdev->lock);
62 }
63
64 size_t
65 serial_readbuf(struct serial_dev* sdev, u8_t* buf, size_t len)
66 {
67     mutex_lock(&sdev->lock);
68
69     size_t rdlen;
70     while (!(rdlen = fifo_read(&sdev->rxbuf, buf, len))) {
71         pwait(&sdev->wq_rxdone);
72     }
73
74     mutex_unlock(&sdev->lock);
75
76     return rdlen;
77 }
78
79 int
80 serial_readbuf_nowait(struct serial_dev* sdev, u8_t* buf, size_t len)
81 {
82     mutex_lock(&sdev->lock);
83
84     int rdlen = fifo_read(&sdev->rxbuf, buf, len);
85
86     mutex_unlock(&sdev->lock);
87
88     return rdlen;
89 }
90
91 int
92 serial_writebuf(struct serial_dev* sdev, u8_t* buf, size_t len)
93 {
94     mutex_lock(&sdev->lock);
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     mutex_unlock(&sdev->lock);
105
106     return rdlen;
107 }
108
109 int
110 serial_writebuf_nowait(struct serial_dev* sdev, u8_t* buf, size_t len)
111 {
112     mutex_lock(&sdev->lock);
113
114     sdev->write(sdev, buf, len);
115     int rdlen = sdev->wr_len;
116
117     mutex_unlock(&sdev->lock);
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()
162 {
163     struct serial_dev* sdev = valloc(sizeof(struct serial_dev));
164     struct device* dev = device_addseq(NULL, sdev, "ttyS%d", serial_idx++);
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     return sdev;
181 }
182
183 struct serial_dev*
184 serial_get_avilable()
185 {
186     struct serial_dev *pos, *n;
187     llist_for_each(pos, n, &serial_devs, sdev_list)
188     {
189         if (!mutex_on_hold(&pos->lock)) {
190             return pos;
191         }
192     }
193
194     return NULL;
195 }