source: rtems-libbsd/rtemsbsd/rtems/rtems-kernel-termioskqueuepoll.c @ 83574df

55-freebsd-126-freebsd-12
Last change on this file since 83574df was 83574df, checked in by Sebastian Huber <sebastian.huber@…>, on 07/11/17 at 08:42:32

termios: Interrupt server API changes

  • Property mode set to 100644
File size: 6.5 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        rtems_status_code sc;
158
159        ts = arg;
160        tty = ts->tty;
161
162        sc = rtems_semaphore_obtain(tty->isem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
163        BSD_ASSERT(sc == RTEMS_SUCCESSFUL);
164
165        selwakeup(&ts->sel);
166
167        sc = rtems_semaphore_release(tty->isem);
168        BSD_ASSERT(sc == RTEMS_SUCCESSFUL);
169}
170
171static void
172termios_transmit_wakeup(void *arg)
173{
174        termios_selinfo *ts;
175        rtems_termios_tty *tty;
176        rtems_status_code sc;
177
178        ts = arg;
179        tty = ts->tty;
180
181        sc = rtems_semaphore_obtain(tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
182        BSD_ASSERT(sc == RTEMS_SUCCESSFUL);
183
184        selwakeup(&ts->sel);
185
186        sc = rtems_semaphore_release(tty->osem);
187        BSD_ASSERT(sc == RTEMS_SUCCESSFUL);
188}
189
190static void
191termios_wakeup(struct termios *term, void *arg)
192{
193        termios_selinfo *ts = arg;
194
195        rtems_interrupt_server_request_submit(&ts->request);
196}
197
198static struct selinfo *
199termios_get_selinfo(rtems_termios_tty *tty, struct ttywakeup *wk,
200    rtems_interrupt_handler handler)
201{
202        termios_selinfo *ts = wk->sw_arg;
203
204        if (ts == NULL) {
205                BSD_ASSERT(wk->sw_pfn == NULL);
206                ts = malloc(sizeof(*ts), M_TEMP, M_WAITOK | M_ZERO);
207                ts->tty = tty;
208                rtems_interrupt_server_request_initialize(RTEMS_INTERRUPT_SERVER_DEFAULT,
209                    &ts->request, handler, ts);
210                wk->sw_arg = ts;
211                wk->sw_pfn = termios_wakeup;
212        } else {
213                BSD_ASSERT(wk->sw_pfn == termios_wakeup);
214        }
215
216        return (&ts->sel);
217}
218
219int
220rtems_termios_kqfilter(rtems_libio_t *iop, struct knote  *kn)
221{
222
223        return (EINVAL);
224}
225
226int
227rtems_termios_poll(rtems_libio_t *iop, int events)
228{
229        struct thread *td = rtems_bsd_get_curthread_or_wait_forever();
230        struct selinfo *sel;
231        rtems_termios_tty *tty;
232        rtems_status_code sc;
233        int revents;
234
235        revents = 0;
236        tty = iop->data1;
237
238        if ((events & (POLLIN | POLLRDNORM)) != 0) {
239                sel = termios_get_selinfo(tty, &tty->tty_rcv,
240                    termios_receive_wakeup);
241
242                sc = rtems_semaphore_obtain(tty->isem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
243                BSD_ASSERT(sc == RTEMS_SUCCESSFUL);
244
245                if (termios_can_read(tty)) {
246                        revents |= events & (POLLIN | POLLRDNORM);
247                } else {
248                        selrecord(td, sel);
249                }
250
251                sc = rtems_semaphore_release(tty->isem);
252                BSD_ASSERT(sc == RTEMS_SUCCESSFUL);
253        }
254
255        if ((events & (POLLOUT | POLLWRNORM)) != 0) {
256                sel = termios_get_selinfo(tty, &tty->tty_snd,
257                    termios_transmit_wakeup);
258
259                sc = rtems_semaphore_obtain(tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
260                BSD_ASSERT(sc == RTEMS_SUCCESSFUL);
261
262                if (termios_can_write(tty)) {
263                        revents |= events & (POLLOUT | POLLWRNORM);
264                } else {
265                        selrecord(td, sel);
266                }
267
268                sc = rtems_semaphore_release(tty->osem);
269                BSD_ASSERT(sc == RTEMS_SUCCESSFUL);
270        }
271
272        return (revents);
273}
274
275static void
276termioskqueuepoll_sysinit(void)
277{
278
279        /* Do nothing */
280}
281
282SYSINIT(termioskqueuepoll, SI_SUB_TUNABLES, SI_ORDER_ANY,
283    termioskqueuepoll_sysinit, NULL);
Note: See TracBrowser for help on using the repository browser.