diff --git a/extmod/misc.h b/extmod/misc.h
index dae6bec4a10fcf966fb13aa6c8d55bd4a9be7b54..40b091e5f73d52300f9b3277cdec27d1db9b746d 100644
--- a/extmod/misc.h
+++ b/extmod/misc.h
@@ -36,6 +36,7 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj);
 
 #if MICROPY_PY_OS_DUPTERM
 bool mp_uos_dupterm_is_builtin_stream(mp_const_obj_t stream);
+uintptr_t mp_uos_dupterm_poll(uintptr_t poll_flags);
 int mp_uos_dupterm_rx_chr(void);
 void mp_uos_dupterm_tx_strn(const char *str, size_t len);
 void mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc);
diff --git a/extmod/uos_dupterm.c b/extmod/uos_dupterm.c
index 42cb21444b010148821acdcebd10040153a63b53..9a8f0af4ed2456a559bf0f0ceeca11820826a184 100644
--- a/extmod/uos_dupterm.c
+++ b/extmod/uos_dupterm.c
@@ -4,7 +4,7 @@
  * The MIT License (MIT)
  *
  * Copyright (c) 2016 Paul Sokolovsky
- * Copyright (c) 2017 Damien P. George
+ * Copyright (c) 2017-2019 Damien P. George
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -53,6 +53,45 @@ void mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc) {
     }
 }
 
+uintptr_t mp_uos_dupterm_poll(uintptr_t poll_flags) {
+    uintptr_t poll_flags_out = 0;
+
+    for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) {
+        mp_obj_t s = MP_STATE_VM(dupterm_objs[idx]);
+        if (s == MP_OBJ_NULL) {
+            continue;
+        }
+
+        int errcode = 0;
+        mp_uint_t ret = 0;
+        const mp_stream_p_t *stream_p = mp_get_stream(s);
+        #if MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM
+        if (mp_uos_dupterm_is_builtin_stream(s)) {
+            ret = stream_p->ioctl(s, MP_STREAM_POLL, poll_flags, &errcode);
+        } else
+        #endif
+        {
+            nlr_buf_t nlr;
+            if (nlr_push(&nlr) == 0) {
+                ret = stream_p->ioctl(s, MP_STREAM_POLL, poll_flags, &errcode);
+                nlr_pop();
+            } else {
+                // Ignore error with ioctl
+            }
+        }
+
+        if (ret != MP_STREAM_ERROR) {
+            poll_flags_out |= ret;
+            if (poll_flags_out == poll_flags) {
+                // Finish early if all requested flags are set
+                break;
+            }
+        }
+    }
+
+    return poll_flags_out;
+}
+
 int mp_uos_dupterm_rx_chr(void) {
     for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) {
         if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) {