source: rtems-libbsd/rtemsbsd/rtems/rtems-kernel-termioskqueuepoll.c @ 8b3da13

55-freebsd-126-freebsd-12
Last change on this file since 8b3da13 was 8b3da13, checked in by Sebastian Huber <sebastian.huber@…>, on 01/08/18 at 12:55:36

termios: Update due to API changes

Update #2843.

  • Property mode set to 100644
File size: 6.0 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup rtems_bsd_rtems
5 *
6 * @brief TODO.
7 */
8
9/*
10 * Copyright (c) 2017 embedded brains GmbH.
11 * All rights reserved.
12 *
13 *  embedded brains GmbH
14 *  Dornierstr. 4
15 *  82178 Puchheim
16 *  Germany
17 *  <rtems@embedded-brains.de>
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
21 * are met:
22 * 1. Redistributions of source code must retain the above copyright
23 *    notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright
25 *    notice, this list of conditions and the following disclaimer in the
26 *    documentation and/or other materials provided with the distribution.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 */
40
41#include <machine/rtems-bsd-kernel-space.h>
42
43#include <sys/cdefs.h>
44#include <sys/types.h>
45#include <sys/errno.h>
46#include <sys/event.h>
47#include <sys/kernel.h>
48#include <sys/malloc.h>
49#include <sys/pcpu.h>
50#include <sys/poll.h>
51#include <sys/selinfo.h>
52
53#include <rtems/termiostypes.h>
54#include <rtems/irq-extension.h>
55
56SYSINIT_REFERENCE(irqs);
57
58typedef struct {
59        rtems_termios_tty *tty;
60        struct selinfo sel;
61        rtems_interrupt_server_request request;
62} termios_selinfo;
63
64static bool
65termios_is_eol(const rtems_termios_tty *tty, char c)
66{
67
68        return (c == '\n' || c == tty->termios.c_cc[VEOF] ||
69            c == tty->termios.c_cc[VEOL] ||
70            c == tty->termios.c_cc[VEOL2]);
71}
72
73static bool
74termios_can_read(rtems_termios_tty *tty)
75{
76        rtems_termios_device_context *ctx;
77        rtems_interrupt_lock_context lock_context;
78        unsigned int i;
79        unsigned int size;
80        unsigned int raw_content_size;
81        bool can;
82
83        if (tty->handler.mode == TERMIOS_POLLED) {
84                return (true);
85        }
86
87        if (tty->cindex != tty->ccount) {
88                return (true);
89        }
90
91        ctx = tty->device_context;
92        rtems_termios_device_lock_acquire(ctx, &lock_context);
93        i = tty->rawInBuf.Head;
94        size = tty->rawInBuf.Size;
95        raw_content_size = (tty->rawInBuf.Tail - i) % size;
96
97        if ((tty->termios.c_lflag & ICANON) != 0) {
98                unsigned int todo = raw_content_size;
99
100                /*
101                 * FIXME: What to do in case of a raw input buffer overflow?
102                 * For now, indicated that we can read.  However, this has
103                 * problems in case an erase takes place.
104                 */
105                can = raw_content_size == (size - 1);
106
107                while (todo > 0 && !can) {
108                        char c;
109
110                        i = (i + 1) % size;
111                        c = tty->rawInBuf.theBuf[i];
112                        can = termios_is_eol(tty, c);
113                        --todo;
114                }
115        } else {
116                cc_t vmin = tty->termios.c_cc[VMIN];
117
118                if (vmin == 0) {
119                        vmin = 1;
120                }
121
122                can = raw_content_size >= vmin;
123        }
124
125        if (!can) {
126                tty->tty_rcvwakeup = false;
127        }
128
129        rtems_termios_device_lock_release(ctx, &lock_context);
130        return (can);
131}
132
133static bool
134termios_can_write(const rtems_termios_tty *tty)
135{
136        rtems_termios_device_context *ctx;
137        rtems_interrupt_lock_context lock_context;
138        bool can;
139
140        if (tty->handler.mode == TERMIOS_POLLED) {
141                return (true);
142        }
143
144        ctx = tty->device_context;
145        rtems_termios_device_lock_acquire(ctx, &lock_context);
146        can = ((tty->rawOutBuf.Tail - tty->rawOutBuf.Head - 1) %
147            tty->rawOutBuf.Size) > 0;
148        rtems_termios_device_lock_release(ctx, &lock_context);
149        return (can);
150}
151
152static void
153termios_receive_wakeup(void *arg)
154{
155        termios_selinfo *ts;
156        rtems_termios_tty *tty;
157
158        ts = arg;
159        tty = ts->tty;
160
161        rtems_mutex_lock(&tty->isem);
162        selwakeup(&ts->sel);
163        rtems_mutex_unlock(&tty->isem);
164}
165
166static void
167termios_transmit_wakeup(void *arg)
168{
169        termios_selinfo *ts;
170        rtems_termios_tty *tty;
171
172        ts = arg;
173        tty = ts->tty;
174
175        rtems_mutex_lock(&tty->osem);
176        selwakeup(&ts->sel);
177        rtems_mutex_unlock(&tty->osem);
178}
179
180static void
181termios_wakeup(struct termios *term, void *arg)
182{
183        termios_selinfo *ts = arg;
184
185        rtems_interrupt_server_request_submit(&ts->request);
186}
187
188static struct selinfo *
189termios_get_selinfo(rtems_termios_tty *tty, struct ttywakeup *wk,
190    rtems_interrupt_handler handler)
191{
192        termios_selinfo *ts = wk->sw_arg;
193
194        if (ts == NULL) {
195                BSD_ASSERT(wk->sw_pfn == NULL);
196                ts = malloc(sizeof(*ts), M_TEMP, M_WAITOK | M_ZERO);
197                ts->tty = tty;
198                rtems_interrupt_server_request_initialize(RTEMS_INTERRUPT_SERVER_DEFAULT,
199                    &ts->request, handler, ts);
200                wk->sw_arg = ts;
201                wk->sw_pfn = termios_wakeup;
202        } else {
203                BSD_ASSERT(wk->sw_pfn == termios_wakeup);
204        }
205
206        return (&ts->sel);
207}
208
209int
210rtems_termios_kqfilter(rtems_libio_t *iop, struct knote  *kn)
211{
212
213        return (EINVAL);
214}
215
216int
217rtems_termios_poll(rtems_libio_t *iop, int events)
218{
219        struct thread *td = rtems_bsd_get_curthread_or_wait_forever();
220        struct selinfo *sel;
221        rtems_termios_tty *tty;
222        int revents;
223
224        revents = 0;
225        tty = iop->data1;
226
227        if ((events & (POLLIN | POLLRDNORM)) != 0) {
228                sel = termios_get_selinfo(tty, &tty->tty_rcv,
229                    termios_receive_wakeup);
230
231                rtems_mutex_lock(&tty->isem);
232
233                if (termios_can_read(tty)) {
234                        revents |= events & (POLLIN | POLLRDNORM);
235                } else {
236                        selrecord(td, sel);
237                }
238
239                rtems_mutex_unlock(&tty->isem);
240        }
241
242        if ((events & (POLLOUT | POLLWRNORM)) != 0) {
243                sel = termios_get_selinfo(tty, &tty->tty_snd,
244                    termios_transmit_wakeup);
245
246                rtems_mutex_lock(&tty->osem);
247
248                if (termios_can_write(tty)) {
249                        revents |= events & (POLLOUT | POLLWRNORM);
250                } else {
251                        selrecord(td, sel);
252                }
253
254                rtems_mutex_unlock(&tty->osem);
255        }
256
257        return (revents);
258}
259
260static void
261termioskqueuepoll_sysinit(void)
262{
263
264        /* Do nothing */
265}
266
267SYSINIT(termioskqueuepoll, SI_SUB_TUNABLES, SI_ORDER_ANY,
268    termioskqueuepoll_sysinit, NULL);
Note: See TracBrowser for help on using the repository browser.