aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tmk_core/protocol/chibios/usb_driver.c14
-rw-r--r--tmk_core/protocol/chibios/usb_main.c29
-rw-r--r--tmk_core/protocol/lufa/lufa.c11
3 files changed, 33 insertions, 21 deletions
diff --git a/tmk_core/protocol/chibios/usb_driver.c b/tmk_core/protocol/chibios/usb_driver.c
index 40bfb8eb2..cc0ce7600 100644
--- a/tmk_core/protocol/chibios/usb_driver.c
+++ b/tmk_core/protocol/chibios/usb_driver.c
@@ -80,19 +80,7 @@ static bool qmkusb_start_receive(QMKUSBDriver *qmkusbp) {
80 * Interface implementation. 80 * Interface implementation.
81 */ 81 */
82 82
83static size_t _write(void *ip, const uint8_t *bp, size_t n) { 83static size_t _write(void *ip, const uint8_t *bp, size_t n) { return obqWriteTimeout(&((QMKUSBDriver *)ip)->obqueue, bp, n, TIME_INFINITE); }
84 output_buffers_queue_t *obqueue = &((QMKUSBDriver *)ip)->obqueue;
85 chSysLock();
86 const bool full = obqIsFullI(obqueue);
87 chSysUnlock();
88 if (full || bqIsSuspendedX(obqueue)) {
89 /* Discard any writes while the queue is suspended or full, i.e. the hidraw
90 interface is not open. If we tried to send with an infinite timeout, we
91 would deadlock the keyboard otherwise. */
92 return -1;
93 }
94 return obqWriteTimeout(obqueue, bp, n, TIME_INFINITE);
95}
96 84
97static size_t _read(void *ip, uint8_t *bp, size_t n) { return ibqReadTimeout(&((QMKUSBDriver *)ip)->ibqueue, bp, n, TIME_INFINITE); } 85static size_t _read(void *ip, uint8_t *bp, size_t n) { return ibqReadTimeout(&((QMKUSBDriver *)ip)->ibqueue, bp, n, TIME_INFINITE); }
98 86
diff --git a/tmk_core/protocol/chibios/usb_main.c b/tmk_core/protocol/chibios/usb_main.c
index 8adecfa71..0703cdc71 100644
--- a/tmk_core/protocol/chibios/usb_main.c
+++ b/tmk_core/protocol/chibios/usb_main.c
@@ -930,9 +930,32 @@ void send_consumer(uint16_t data) {
930#ifdef CONSOLE_ENABLE 930#ifdef CONSOLE_ENABLE
931 931
932int8_t sendchar(uint8_t c) { 932int8_t sendchar(uint8_t c) {
933 // The previous implmentation had timeouts, but I think it's better to just slow down 933 static bool timed_out = false;
934 // and make sure that everything is transferred, rather than dropping stuff 934 /* The `timed_out` state is an approximation of the ideal `is_listener_disconnected?` state.
935 return chnWrite(&drivers.console_driver.driver, &c, 1); 935 *
936 * When a 5ms timeout write has timed out, hid_listen is most likely not running, or not
937 * listening to this keyboard, so we go into the timed_out state. In this state we assume
938 * that hid_listen is most likely not gonna be connected to us any time soon, so it would
939 * be wasteful to write follow-up characters with a 5ms timeout, it would all add up and
940 * unncecessarily slow down the firmware. However instead of just dropping the characters,
941 * we write them with a TIME_IMMEDIATE timeout, which is a zero timeout,
942 * and this will succeed only if hid_listen gets connected again. When a write with
943 * TIME_IMMEDIATE timeout succeeds, we know that hid_listen is listening to us again, and
944 * we can go back to the timed_out = false state, and following writes will be executed
945 * with a 5ms timeout. The reason we don't just send all characters with the TIME_IMMEDIATE
946 * timeout is that this could cause bytes to be lost even if hid_listen is running, if there
947 * is a lot of data being sent over the console.
948 *
949 * This logic will work correctly as long as hid_listen is able to receive at least 200
950 * bytes per second. On a heavily overloaded machine that's so overloaded that it's
951 * unusable, and constantly swapping, hid_listen might have trouble receiving 200 bytes per
952 * second, so some bytes might be lost on the console.
953 */
954
955 const sysinterval_t timeout = timed_out ? TIME_IMMEDIATE : TIME_MS2I(5);
956 const size_t result = chnWriteTimeout(&drivers.console_driver.driver, &c, 1, timeout);
957 timed_out = (result == 0);
958 return result;
936} 959}
937 960
938// Just a dummy function for now, this could be exposed as a weak function 961// Just a dummy function for now, this could be exposed as a weak function
diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c
index f1908b3d0..85d71d083 100644
--- a/tmk_core/protocol/lufa/lufa.c
+++ b/tmk_core/protocol/lufa/lufa.c
@@ -829,9 +829,10 @@ static void send_consumer(uint16_t data) {
829 * FIXME: Needs doc 829 * FIXME: Needs doc
830 */ 830 */
831int8_t sendchar(uint8_t c) { 831int8_t sendchar(uint8_t c) {
832 // Not wait once timeouted. 832 // Do not wait if the previous write has timed_out.
833 // Because sendchar() is called so many times, waiting each call causes big lag. 833 // Because sendchar() is called so many times, waiting each call causes big lag.
834 static bool timeouted = false; 834 // The `timed_out` state is an approximation of the ideal `is_listener_disconnected?` state.
835 static bool timed_out = false;
835 836
836 // prevents Console_Task() from running during sendchar() runs. 837 // prevents Console_Task() from running during sendchar() runs.
837 // or char will be lost. These two function is mutually exclusive. 838 // or char will be lost. These two function is mutually exclusive.
@@ -845,11 +846,11 @@ int8_t sendchar(uint8_t c) {
845 goto ERROR_EXIT; 846 goto ERROR_EXIT;
846 } 847 }
847 848
848 if (timeouted && !Endpoint_IsReadWriteAllowed()) { 849 if (timed_out && !Endpoint_IsReadWriteAllowed()) {
849 goto ERROR_EXIT; 850 goto ERROR_EXIT;
850 } 851 }
851 852
852 timeouted = false; 853 timed_out = false;
853 854
854 uint8_t timeout = SEND_TIMEOUT; 855 uint8_t timeout = SEND_TIMEOUT;
855 while (!Endpoint_IsReadWriteAllowed()) { 856 while (!Endpoint_IsReadWriteAllowed()) {
@@ -860,7 +861,7 @@ int8_t sendchar(uint8_t c) {
860 goto ERROR_EXIT; 861 goto ERROR_EXIT;
861 } 862 }
862 if (!(timeout--)) { 863 if (!(timeout--)) {
863 timeouted = true; 864 timed_out = true;
864 goto ERROR_EXIT; 865 goto ERROR_EXIT;
865 } 866 }
866 _delay_ms(1); 867 _delay_ms(1);