mirror of
https://github.com/candle-usb/candleLight_fw.git
synced 2025-01-28 06:02:52 +08:00
Clean up the USB interrupt interactions
This might fix candle-usb/candleLight_fw#58. It definitely makes it so I no longer observe similar behavior with multiple hosts running gs_usb.
This commit is contained in:
parent
d66fda39f8
commit
2225fc0290
@ -52,10 +52,6 @@ typedef struct {
|
||||
|
||||
can_data_t *channels[NUM_CAN_CHANNEL];
|
||||
|
||||
uint32_t out_requests;
|
||||
uint32_t out_requests_fail;
|
||||
uint32_t out_requests_no_buf;
|
||||
|
||||
led_data_t *leds;
|
||||
bool dfu_detach_requested;
|
||||
|
||||
@ -63,7 +59,6 @@ typedef struct {
|
||||
uint32_t sof_timestamp_us;
|
||||
|
||||
bool pad_pkts_to_max_pkt_size;
|
||||
|
||||
} USBD_GS_CAN_HandleTypeDef __attribute__ ((aligned (4)));
|
||||
|
||||
static uint8_t USBD_GS_CAN_Start(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
|
||||
@ -287,6 +282,14 @@ static const struct gs_device_bt_const USBD_GS_CAN_btconst = {
|
||||
1, // brp increment;
|
||||
};
|
||||
|
||||
/* It's unclear from the documentation, but it appears that the USB library is
|
||||
* not safely reentrant. It attempts to signal errors via return values if it is
|
||||
* reentered, but that code is not interrupt-safe and the error values are
|
||||
* silently ignored within the library in several cases. We'll just disable
|
||||
* interrupts at all entry points to be safe. Note that the callbacks are all
|
||||
* called from within the libary itself, either within the interrupt handler or
|
||||
* within other calls, which means the USB interrupt is already disabled and we
|
||||
* don't have any other interrupts to worry about. */
|
||||
|
||||
uint8_t USBD_GS_CAN_Init(USBD_HandleTypeDef *pdev, queue_t *q_frame_pool, queue_t *q_from_host, led_data_t *leds)
|
||||
{
|
||||
@ -446,7 +449,7 @@ static uint8_t USBD_GS_CAN_DFU_Request(USBD_HandleTypeDef *pdev, USBD_SetupReqTy
|
||||
hcan->dfu_detach_requested = true;
|
||||
break;
|
||||
|
||||
case 3: // GET_STATIS request
|
||||
case 3: // GET_STATUS request
|
||||
hcan->ep0_buf[0] = 0x00; // bStatus: 0x00 == OK
|
||||
hcan->ep0_buf[1] = 0x00; // bwPollTimeout
|
||||
hcan->ep0_buf[2] = 0x00;
|
||||
@ -595,30 +598,31 @@ static uint8_t USBD_GS_CAN_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) {
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
// Note that the return value is completely ignored by the stack.
|
||||
static uint8_t USBD_GS_CAN_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) {
|
||||
|
||||
uint8_t retval = USBD_FAIL;
|
||||
|
||||
USBD_GS_CAN_HandleTypeDef *hcan = (USBD_GS_CAN_HandleTypeDef*)pdev->pClassData;
|
||||
|
||||
hcan->out_requests++;
|
||||
|
||||
uint32_t rxlen = USBD_LL_GetRxDataSize(pdev, epnum);
|
||||
if (rxlen >= (sizeof(struct gs_host_frame)-4)) {
|
||||
struct gs_host_frame *frame = queue_pop_front_i(hcan->q_frame_pool);
|
||||
if(frame){
|
||||
queue_push_back_i(hcan->q_from_host, hcan->from_host_buf);
|
||||
hcan->from_host_buf = frame;
|
||||
|
||||
retval = USBD_OK;
|
||||
}
|
||||
else{
|
||||
// Discard current packet from host if we have no place
|
||||
// to put the next one
|
||||
}
|
||||
if (rxlen < (sizeof(struct gs_host_frame)-4)) {
|
||||
// Invalid frame length, just ignore it and receive into the same buffer
|
||||
// again next time.
|
||||
USBD_GS_CAN_PrepareReceive(pdev);
|
||||
return USBD_OK;
|
||||
}
|
||||
USBD_GS_CAN_PrepareReceive(pdev);
|
||||
return retval;
|
||||
|
||||
// Enqueue the frame we just received.
|
||||
queue_push_back(hcan->q_from_host, hcan->from_host_buf);
|
||||
// Grab a buffer for the next frame from the pool.
|
||||
hcan->from_host_buf = queue_pop_front(hcan->q_frame_pool);
|
||||
if (hcan->from_host_buf) {
|
||||
// We got a buffer! Get ready to receive from the USB host into it.
|
||||
USBD_GS_CAN_PrepareReceive(pdev);
|
||||
} else {
|
||||
// gs_can has no way to drop packets. If we just drop this one, gs_can
|
||||
// will fill up its queue of packets awaiting ACKs and then hang. Instead,
|
||||
// wait to call PrepareReceive until we have a frame to receive into.
|
||||
}
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
static uint8_t *USBD_GS_CAN_GetCfgDesc(uint16_t *len)
|
||||
@ -637,7 +641,16 @@ inline uint8_t USBD_GS_CAN_PrepareReceive(USBD_HandleTypeDef *pdev)
|
||||
bool USBD_GS_CAN_TxReady(USBD_HandleTypeDef *pdev)
|
||||
{
|
||||
USBD_GS_CAN_HandleTypeDef *hcan = (USBD_GS_CAN_HandleTypeDef*)pdev->pClassData;
|
||||
return hcan->TxState == 0;
|
||||
int primask = disable_irq();
|
||||
if (!hcan->from_host_buf) {
|
||||
hcan->from_host_buf = queue_pop_front(hcan->q_frame_pool);
|
||||
if (hcan->from_host_buf) {
|
||||
USBD_GS_CAN_PrepareReceive(pdev);
|
||||
}
|
||||
}
|
||||
bool result = hcan->TxState == 0;
|
||||
enable_irq(primask);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t USBD_GS_CAN_Transmit(USBD_HandleTypeDef *pdev, uint8_t *buf, uint16_t len)
|
||||
@ -694,7 +707,10 @@ uint8_t USBD_GS_CAN_SendFrame(USBD_HandleTypeDef *pdev, struct gs_host_frame *fr
|
||||
len = sizeof(buf);
|
||||
}
|
||||
|
||||
return USBD_GS_CAN_Transmit(pdev, send_addr, len);
|
||||
int primask = disable_irq();
|
||||
uint8_t result = USBD_GS_CAN_Transmit(pdev, send_addr, len);
|
||||
enable_irq(primask);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t *USBD_GS_CAN_GetStrDesc(USBD_HandleTypeDef *pdev, uint8_t index, uint16_t *length)
|
||||
|
Loading…
x
Reference in New Issue
Block a user