From 0cfdd2de3eb189869a7dbfd91ab79ebe9c977b0c Mon Sep 17 00:00:00 2001 From: Kim Streich Date: Wed, 12 Apr 2023 12:02:16 -0600 Subject: [PATCH] drivers: ps2: Add resend callback to ps/2 interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the PS/2 driver detects an error in an incoming transmission, it’s supposed to send 0xfe to the device to ask it to resend the last packet. But a PS/2 packet can be more than one byte (such as a 3 or 4-byte mouse packet). So, on reception of the 0xfe resend command, the PS/2 device resends ALL bytes in the packet and not just the one where the transmission failed. This can cause the higher level driver’s packet buffer to become misaligned. This PR adds a callback that notifies the higher level driver when the PS/2 driver requested a resend so that the higher level driver can expect a new packet and doesn’t get misaligned. --- drivers/ps2/ps2_handlers.c | 8 ++++++-- drivers/ps2/ps2_mchp_xec.c | 3 ++- drivers/ps2/ps2_npcx_channel.c | 3 ++- include/zephyr/drivers/ps2.h | 24 ++++++++++++++++++++---- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/drivers/ps2/ps2_handlers.c b/drivers/ps2/ps2_handlers.c index 71d1181a2d29558..e9501e92fcbbf14 100644 --- a/drivers/ps2/ps2_handlers.c +++ b/drivers/ps2/ps2_handlers.c @@ -8,12 +8,16 @@ #include static inline int z_vrfy_ps2_config(const struct device *dev, - ps2_callback_t callback_isr) + ps2_callback_t callback_isr, + ps2_resend_callback_t resend_callback_isr) + { Z_OOPS(Z_SYSCALL_DRIVER_PS2(dev, config)); Z_OOPS(Z_SYSCALL_VERIFY_MSG(callback_isr == NULL, "callback not be set from user mode")); - return z_impl_ps2_config(dev, callback_isr); + Z_OOPS(Z_SYSCALL_VERIFY_MSG(resend_callback_isr == NULL, + "resend callback not be set from user mode")); + return z_impl_ps2_config(dev, callback_isr, resend_callback_isr); } #include diff --git a/drivers/ps2/ps2_mchp_xec.c b/drivers/ps2/ps2_mchp_xec.c index c9b43a7ea401d71..76cec3dedd4190c 100644 --- a/drivers/ps2/ps2_mchp_xec.c +++ b/drivers/ps2/ps2_mchp_xec.c @@ -94,7 +94,8 @@ static inline void ps2_xec_girq_en(const struct device *dev) #endif /* CONFIG_SOC_SERIES_MEC172X */ static int ps2_xec_configure(const struct device *dev, - ps2_callback_t callback_isr) + ps2_callback_t callback_isr, + ps2_resend_callback_t resend_callback_isr) { const struct ps2_xec_config * const config = dev->config; struct ps2_xec_data * const data = dev->data; diff --git a/drivers/ps2/ps2_npcx_channel.c b/drivers/ps2/ps2_npcx_channel.c index b71886013998237..7bf29d6f38d2df5 100644 --- a/drivers/ps2/ps2_npcx_channel.c +++ b/drivers/ps2/ps2_npcx_channel.c @@ -37,7 +37,8 @@ struct ps2_npcx_ch_config { /* PS/2 api functions */ static int ps2_npcx_ch_configure(const struct device *dev, - ps2_callback_t callback_isr) + ps2_callback_t callback_isr, + ps2_resend_callback_t resend_callback_isr) { const struct ps2_npcx_ch_config *const config = dev->config; int ret; diff --git a/include/zephyr/drivers/ps2.h b/include/zephyr/drivers/ps2.h index a48195020c83cce..004d8047e3b570d 100644 --- a/include/zephyr/drivers/ps2.h +++ b/include/zephyr/drivers/ps2.h @@ -37,6 +37,18 @@ extern "C" { */ typedef void (*ps2_callback_t)(const struct device *dev, uint8_t data); +/** + * @brief PS/2 callback that is called when the PS/2 driver detects a + * transmission error and instructs the PS/2 device to re-send the last PS/2 + * packet. A PS/2 packet can be more than one byte and when the device is + * instructed to resend the last packet, it will resend all the bytes. This + * can cause the PS/2 driver to become misaligned. This callback lets the PS/2 + * driver know that it should expect a resend of an entire packet. + * + * @param dev Pointer to the device structure for the driver instance. + */ +typedef void (*ps2_resend_callback_t)(const struct device *dev); + /** * @cond INTERNAL_HIDDEN * @@ -45,7 +57,8 @@ typedef void (*ps2_callback_t)(const struct device *dev, uint8_t data); * (Internal use only.) */ typedef int (*ps2_config_t)(const struct device *dev, - ps2_callback_t callback_isr); + ps2_callback_t callback_isr, + ps2_resend_callback_t resend_callback_isr); typedef int (*ps2_read_t)(const struct device *dev, uint8_t *value); typedef int (*ps2_write_t)(const struct device *dev, uint8_t value); typedef int (*ps2_disable_callback_t)(const struct device *dev); @@ -73,15 +86,18 @@ __subsystem struct ps2_driver_api { * @retval Negative errno code if failure. */ __syscall int ps2_config(const struct device *dev, - ps2_callback_t callback_isr); + ps2_callback_t callback_isr, + ps2_resend_callback_t resend_callback_isr); static inline int z_impl_ps2_config(const struct device *dev, - ps2_callback_t callback_isr) + ps2_callback_t callback_isr, + ps2_resend_callback_t resend_callback_isr) + { const struct ps2_driver_api *api = (struct ps2_driver_api *)dev->api; - return api->config(dev, callback_isr); + return api->config(dev, callback_isr, resend_callback_isr); } /**