diff --git a/include/libopencm3/usb/usbd.h b/include/libopencm3/usb/usbd.h index fab63046..c73de072 100644 --- a/include/libopencm3/usb/usbd.h +++ b/include/libopencm3/usb/usbd.h @@ -65,6 +65,8 @@ extern u16 usbd_ep_read_packet(u8 addr, void *buf, u16 len); extern void usbd_ep_stall_set(u8 addr, u8 stall); extern u8 usbd_ep_stall_get(u8 addr); +extern void usbd_ep_nak_set(u8 addr, u8 nak); + /* Optional */ extern void usbd_cable_connect(u8 on); diff --git a/lib/usb/usb.c b/lib/usb/usb.c index eb8e6d82..59c526dd 100644 --- a/lib/usb/usb.c +++ b/lib/usb/usb.c @@ -127,3 +127,9 @@ u8 usbd_ep_stall_get(u8 addr) { return _usbd_device.driver->ep_stall_get(addr); } + +void usbd_ep_nak_set(u8 addr, u8 nak) +{ + _usbd_device.driver->ep_nak_set(addr, nak); +} + diff --git a/lib/usb/usb_f103.c b/lib/usb/usb_f103.c index ef97670f..19f645d1 100644 --- a/lib/usb/usb_f103.c +++ b/lib/usb/usb_f103.c @@ -30,10 +30,13 @@ static void stm32f103_ep_setup(u8 addr, u8 type, u16 max_size, static void stm32f103_endpoints_reset(void); static void stm32f103_ep_stall_set(u8 addr, u8 stall); static u8 stm32f103_ep_stall_get(u8 addr); +static void stm32f103_ep_nak_set(u8 addr, u8 nak); static u16 stm32f103_ep_write_packet(u8 addr, const void *buf, u16 len); static u16 stm32f103_ep_read_packet(u8 addr, void *buf, u16 len); static void stm32f103_poll(void); +static u8 force_nak[8]; + const struct _usbd_driver stm32f103_usb_driver = { .init = stm32f103_usbd_init, .set_address = stm32f103_set_address, @@ -41,6 +44,7 @@ const struct _usbd_driver stm32f103_usb_driver = { .ep_reset = stm32f103_endpoints_reset, .ep_stall_set = stm32f103_ep_stall_set, .ep_stall_get = stm32f103_ep_stall_get, + .ep_nak_set = stm32f103_ep_nak_set, .ep_write_packet = stm32f103_ep_write_packet, .ep_read_packet = stm32f103_ep_read_packet, .poll = stm32f103_poll, @@ -177,6 +181,20 @@ static u8 stm32f103_ep_stall_get(u8 addr) return 0; } +static void stm32f103_ep_nak_set(u8 addr, u8 nak) +{ + /* It does not make sence to force NAK on IN endpoints */ + if(addr & 0x80) + return; + + force_nak[addr] = nak; + + if(nak) + USB_SET_EP_RX_STAT(addr, USB_EP_RX_STAT_NAK); + else + USB_SET_EP_RX_STAT(addr, USB_EP_RX_STAT_VALID); +} + /** * Copy a data buffer to packet memory. * @@ -236,7 +254,8 @@ static u16 stm32f103_ep_read_packet(u8 addr, void *buf, u16 len) usb_copy_from_pm(buf, USB_GET_EP_RX_BUFF(addr), len); USB_CLR_EP_RX_CTR(addr); - USB_SET_EP_RX_STAT(addr, USB_EP_RX_STAT_VALID); + if(!force_nak[addr]) + USB_SET_EP_RX_STAT(addr, USB_EP_RX_STAT_VALID); return len; } diff --git a/lib/usb/usb_f107.c b/lib/usb/usb_f107.c index 9a20b0b3..f106a053 100644 --- a/lib/usb/usb_f107.c +++ b/lib/usb/usb_f107.c @@ -29,6 +29,8 @@ #define RX_FIFO_SIZE 128 static uint16_t fifo_mem_top; +static u8 force_nak[4]; + static void stm32f107_usbd_init(void); static void stm32f107_set_address(u8 addr); static void stm32f107_ep_setup(u8 addr, u8 type, u16 max_size, @@ -36,6 +38,7 @@ static void stm32f107_ep_setup(u8 addr, u8 type, u16 max_size, static void stm32f107_endpoints_reset(void); static void stm32f107_ep_stall_set(u8 addr, u8 stall); static u8 stm32f107_ep_stall_get(u8 addr); +static void stm32f107_ep_nak_set(u8 addr, u8 nak); static u16 stm32f107_ep_write_packet(u8 addr, const void *buf, u16 len); static u16 stm32f107_ep_read_packet(u8 addr, void *buf, u16 len); static void stm32f107_poll(void); @@ -51,6 +54,7 @@ const struct _usbd_driver stm32f107_usb_driver = { .ep_reset = stm32f107_endpoints_reset, .ep_stall_set = stm32f107_ep_stall_set, .ep_stall_get = stm32f107_ep_stall_get, + .ep_nak_set = stm32f107_ep_nak_set, .ep_write_packet = stm32f107_ep_write_packet, .ep_read_packet = stm32f107_ep_read_packet, .poll = stm32f107_poll, @@ -210,6 +214,20 @@ static u8 stm32f107_ep_stall_get(u8 addr) return (OTG_FS_DOEPCTL(addr) & OTG_FS_DOEPCTL0_STALL)?1:0; } +static void stm32f107_ep_nak_set(u8 addr, u8 nak) +{ + /* It does not make sence to force NAK on IN endpoints */ + if(addr & 0x80) + return; + + force_nak[addr] = nak; + + if(nak) + OTG_FS_DOEPCTL(addr) |= OTG_FS_DOEPCTL0_SNAK; + else + OTG_FS_DOEPCTL(addr) |= OTG_FS_DOEPCTL0_CNAK; +} + static u16 stm32f107_ep_write_packet(u8 addr, const void *buf, u16 len) { const u32 *buf32 = buf; @@ -256,7 +274,8 @@ static u16 stm32f107_ep_read_packet(u8 addr, void *buf, u16 len) } OTG_FS_DOEPTSIZ(addr) = doeptsiz[addr]; - OTG_FS_DOEPCTL(addr) |= OTG_FS_DOEPCTL0_EPENA | OTG_FS_DOEPCTL0_CNAK; + OTG_FS_DOEPCTL(addr) |= OTG_FS_DOEPCTL0_EPENA | + (force_nak[addr] ? OTG_FS_DOEPCTL0_SNAK : OTG_FS_DOEPCTL0_CNAK); return len; } diff --git a/lib/usb/usb_private.h b/lib/usb/usb_private.h index 1bc6b3fc..40d59a11 100644 --- a/lib/usb/usb_private.h +++ b/lib/usb/usb_private.h @@ -78,6 +78,7 @@ struct _usbd_driver { void (*ep_setup)(u8 addr, u8 type, u16 max_size, void (*cb)(u8 ep)); void (*ep_reset)(void); void (*ep_stall_set)(u8 addr, u8 stall); + void (*ep_nak_set)(u8 addr, u8 nak); u8 (*ep_stall_get)(u8 addr); u16 (*ep_write_packet)(u8 addr, const void *buf, u16 len); u16 (*ep_read_packet)(u8 addr, void *buf, u16 len);