Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ChibiOS: fix deadlocks when hammering mouse/extra keys #28

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 48 additions & 33 deletions protocol/chibios/usb_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,15 @@ extern bool keyboard_nkro;
#endif /* NKRO_ENABLE */

report_keyboard_t keyboard_report_sent = {{0}};
report_keyboard_t *keyboard_report_not_yet_sent = NULL;
#ifdef MOUSE_ENABLE
report_mouse_t mouse_report_blank = {0};
report_mouse_t *mouse_report_not_yet_sent = NULL;
#endif /* MOUSE_ENABLE */
#ifdef EXTRAKEY_ENABLE
uint8_t extra_report_blank[3] = {0};
report_extra_t extra_report_not_yet_sent;
bool extra_report_waiting = FALSE;
#endif /* EXTRAKEY_ENABLE */

#ifdef CONSOLE_ENABLE
Expand Down Expand Up @@ -1066,17 +1070,23 @@ void send_remote_wakeup(USBDriver *usbp) {

/* keyboard IN callback hander (a kbd report has made it IN) */
void kbd_in_cb(USBDriver *usbp, usbep_t ep) {
/* STUB */
(void)usbp;
(void)ep;
if (keyboard_report_not_yet_sent != NULL) {
osalSysLockFromISR();
usbStartTransmitI(usbp, ep, (uint8_t *)keyboard_report_not_yet_sent, KBD_EPSIZE);
keyboard_report_not_yet_sent = NULL;
osalSysUnlockFromISR();
}
}

#ifdef NKRO_ENABLE
/* nkro IN callback hander (a nkro report has made it IN) */
void nkro_in_cb(USBDriver *usbp, usbep_t ep) {
/* STUB */
(void)usbp;
(void)ep;
if (keyboard_report_not_yet_sent != NULL) {
osalSysLockFromISR();
usbStartTransmitI(usbp, ep, (uint8_t *)keyboard_report_not_yet_sent, sizeof(report_keyboard_t));
keyboard_report_not_yet_sent = NULL;
osalSysUnlockFromISR();
}
}
#endif /* NKRO_ENABLE */

Expand Down Expand Up @@ -1132,41 +1142,30 @@ void send_keyboard(report_keyboard_t *report) {
osalSysUnlock();
return;
}
osalSysUnlock();

#ifdef NKRO_ENABLE
if(keyboard_nkro) { /* NKRO protocol */
/* need to wait until the previous packet has made it through */
/* can rewrite this using the synchronous API, then would wait
* until *after* the packet has been transmitted. I think
* this is more efficient */
/* busy wait, should be short and not very common */
osalSysLock();
/* save the pointer to the current report to send it later */
if(usbGetTransmitStatusI(&USB_DRIVER, NKRO_ENDPOINT)) {
/* Need to either suspend, or loop and call unlock/lock during
* every iteration - otherwise the system will remain locked,
* no interrupts served, so USB not going through as well.
* Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
osalThreadSuspendS(&(&USB_DRIVER)->epc[NKRO_ENDPOINT]->in_state->thread);
keyboard_report_not_yet_sent = report;
osalSysUnlock();
return;
}
usbStartTransmitI(&USB_DRIVER, NKRO_ENDPOINT, (uint8_t *)report, sizeof(report_keyboard_t));
osalSysUnlock();
} else
#endif /* NKRO_ENABLE */
{ /* boot protocol */
/* need to wait until the previous packet has made it through */
/* busy wait, should be short and not very common */
osalSysLock();
/* save the pointer to the current report to send it later */
if(usbGetTransmitStatusI(&USB_DRIVER, KBD_ENDPOINT)) {
/* Need to either suspend, or loop and call unlock/lock during
* every iteration - otherwise the system will remain locked,
* no interrupts served, so USB not going through as well.
* Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
osalThreadSuspendS(&(&USB_DRIVER)->epc[KBD_ENDPOINT]->in_state->thread);
keyboard_report_not_yet_sent = report;
osalSysUnlock();
return;
}
usbStartTransmitI(&USB_DRIVER, KBD_ENDPOINT, (uint8_t *)report, KBD_EPSIZE);
osalSysUnlock();
}
osalSysUnlock();
keyboard_report_sent = *report;
}

Expand All @@ -1179,8 +1178,12 @@ void send_keyboard(report_keyboard_t *report) {

/* mouse IN callback hander (a mouse report has made it IN) */
void mouse_in_cb(USBDriver *usbp, usbep_t ep) {
(void)usbp;
(void)ep;
if (mouse_report_not_yet_sent != NULL) {
osalSysLockFromISR();
usbStartTransmitI(usbp, ep, (uint8_t *)mouse_report_not_yet_sent, sizeof(report_mouse_t));
mouse_report_not_yet_sent = NULL;
osalSysUnlockFromISR();
}
}

void send_mouse(report_mouse_t *report) {
Expand All @@ -1189,14 +1192,17 @@ void send_mouse(report_mouse_t *report) {
osalSysUnlock();
return;
}
osalSysUnlock();

/* TODO: LUFA manually waits for the endpoint to become ready
* for about 10ms for mouse, kbd, system; 1ms for nkro
* is this really needed?
*/

osalSysLock();
if (usbGetTransmitStatusI(&USB_DRIVER, MOUSE_ENDPOINT)) {
mouse_report_not_yet_sent = report;
osalSysUnlock();
return;
}
usbStartTransmitI(&USB_DRIVER, MOUSE_ENDPOINT, (uint8_t *)report, sizeof(report_mouse_t));
osalSysUnlock();
}
Expand All @@ -1216,9 +1222,12 @@ void send_mouse(report_mouse_t *report) {

/* extrakey IN callback hander */
void extra_in_cb(USBDriver *usbp, usbep_t ep) {
/* STUB */
(void)usbp;
(void)ep;
if (extra_report_waiting) {
osalSysLockFromISR();
usbStartTransmitI(usbp, ep, (uint8_t *)&extra_report_not_yet_sent, sizeof(report_extra_t));
extra_report_waiting = FALSE;
osalSysUnlockFromISR();
}
}

static void send_extra_report(uint8_t report_id, uint16_t data) {
Expand All @@ -1233,6 +1242,12 @@ static void send_extra_report(uint8_t report_id, uint16_t data) {
.usage = data
};

if (usbGetTransmitStatusI(&USB_DRIVER, EXTRA_ENDPOINT)) {
extra_report_not_yet_sent = report;
extra_report_waiting = TRUE;
osalSysUnlock();
return;
}
usbStartTransmitI(&USB_DRIVER, EXTRA_ENDPOINT, (uint8_t *)&report, sizeof(report_extra_t));
osalSysUnlock();
}
Expand Down