1 /*
2 * Copyright 2012, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <portability.h>
18 #include <poll.h>
19 #include <poll_portable.h>
20
21 /*
22 *_XOPEN_SOURCE added the ability to not only poll for data coming in or out
23 * but now also the ability to poll for high priority input and output. Though
24 * the normal priority is equivalent to the original I/O it was assigned new bits:
25 * POLLIN Equivalent to POLLRDNORM
26 * POLLOUT Equivalent to POLLWRNORM
27 *
28 * The Linux kernel sets both POLLIN and POLLRDNORM when data is available and sets
29 * both POLLOUT and POLLWRNORM when data can be written; so the new priority BAND bits
30 * just supplement the meaning of the prior POLLIN and POLLOUT bits as well as the
31 * new POLLRDNORM and POLLWRNORM bits.
32 *
33 * The DECNet Protocol can set the poll in priority flag, POLLRDBAND.
34 * ATM as well as a whole bunch of other protocols can set the poll out priority flag,
35 * POLLWRBAND.
36 *
37 * MIPS and SPARC likely assigned the new XOPEN poll out event flags in UNIX well before
38 * UNIX was ported to X86. It appears that Intel chose different bits and that was
39 * established by Linus as the the generic case and later also chosen by ARM.
40 *
41 * POLLWRNORM:0x100 - MIPS used POLLOUT:0x0004, which is equivalent in meaning.
42 *
43 * POLLWRBAND:0x200 - MIPS used 0x0100. which is POLLWRNORM:0x100.
44 *
45 * Summary:
46 * ========
47 * Both Normal and Priority flags can be mapped to MIPS flags (left to right below).
48 * Only the Priority poll out flag can be mapped back to portable because MIPS
49 * is using the same number as POLLOUT for POLLWRNORM (right to left below).
50 *
51 * ARM/GENERIC/PORTABLE MIPS
52 * ==================== ======
53 * POLLIN 0x0001 0x0001
54 * POLLPRI 0x0002 0x0002
55 * POLLOUT 0x0004 <-----+ 0x0004
56 * POLLERR 0x0008 \ 0x0008
57 * POLLHUP 0x0010 \ 0x0010
58 * POLLNVAL 0x0020 \ 0x0020
59 * POLLRDNORM 0x0040 \ 0x0040
60 * POLLRDBAND 0x0080 \ 0x0080
61 * POLLWRNORM 0x0100 -----------+<----> 0x0004
62 * POLLWRBAND 0x0200 <-----------------> 0x0100
63 * POLLMSG 0x0400 0x0400
64 * POLLREMOVE 0x1000 0x1000
65 * POLLRDHUP 0x2000 0x2000
66 *
67 * The loss of the high priority notice for the polling
68 * of output data is likely minor as it was only being used
69 * in DECNet. Also, the poll system call and device poll
70 * implementations processes POLLOUT and POLLWRNORM event
71 * flags the same.
72 */
73
74 #if POLLWRNORM_PORTABLE==POLLWRNORM
75 #error Bad build environment
76 #endif
77
mips_change_portable_events(short portable_events)78 static inline short mips_change_portable_events(short portable_events)
79 {
80 /* MIPS has different POLLWRNORM and POLLWRBAND. */
81 if (portable_events & POLLWRNORM_PORTABLE) {
82 portable_events &= ~POLLWRNORM_PORTABLE;
83 portable_events |= POLLWRNORM;
84 }
85 if (portable_events & POLLWRBAND_PORTABLE) {
86 portable_events &= ~POLLWRBAND_PORTABLE;
87 portable_events |= POLLWRBAND;
88 }
89
90 return portable_events;
91 }
92
change_mips_events(short mips_events)93 static inline short change_mips_events(short mips_events)
94 {
95 /*
96 * MIPS POLLWRNORM equals MIPS POLLOUT, which is the same as POLLOUT_PORTABLE;
97 * so we just map POLLWRBAND to POLLWRBAND_PORTABLE.
98 */
99 if (mips_events & POLLWRBAND) {
100 mips_events &= ~POLLWRBAND;
101 mips_events |= POLLWRBAND_PORTABLE;
102 }
103
104 return mips_events;
105 }
106
107 extern int poll(struct pollfd *, nfds_t, int);
108
WRAP(poll)109 int WRAP(poll)(struct pollfd *fds, nfds_t nfds, int timeout)
110 {
111 nfds_t i;
112 int ret;
113
114 for (i = 0; i < nfds; i++)
115 fds->events = mips_change_portable_events(fds->events);
116
117 ret = REAL(poll)(fds, nfds, timeout);
118
119 for (i = 0; i < nfds; i++) {
120 fds->events = change_mips_events(fds->events);
121 fds->revents = change_mips_events(fds->revents);
122 }
123
124 return ret;
125 }
126