Skip to content

Commit 95af0d4

Browse files
committed
Clean up USB stall handling
1 parent 4dff3a2 commit 95af0d4

8 files changed

Lines changed: 120 additions & 88 deletions

File tree

src/usb/core.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ static bool_t handle_control_request(void)
9797

9898
/* CLEAR_FEATURE(ENDPOINT_HALT): Required by USB spec.
9999
* Reset data toggle and double-buffer ring state. */
100-
usb_clear_halt(req->wIndex);
100+
usb_clear_stall(req->wIndex);
101101

102102
} else if ((req->bmRequestType&0x7f) == 0x21) {
103103

@@ -149,6 +149,12 @@ static void usb_write_ep0(void)
149149
}
150150
}
151151

152+
static void usb_ctrl_stall(void)
153+
{
154+
usb_stall(0x00);
155+
usb_stall(0x80);
156+
}
157+
152158
void handle_rx_ep0(bool_t is_setup)
153159
{
154160
bool_t ready = FALSE;
@@ -165,7 +171,7 @@ void handle_rx_ep0(bool_t is_setup)
165171
} else if (ep0.data_len < 0) {
166172

167173
/* Unexpected Transaction */
168-
usb_stall(0);
174+
usb_ctrl_stall();
169175
usb_read(ep, NULL, 0);
170176

171177
} else if (ep0_data_out()) {
@@ -199,7 +205,7 @@ void handle_rx_ep0(bool_t is_setup)
199205
if (!handle_control_request()) {
200206

201207
/* Unhandled Control Transfer: STALL */
202-
usb_stall(0);
208+
usb_ctrl_stall();
203209
ep0.data_len = -1; /* Complete */
204210

205211
} else if (ep0_data_in()) {

src/usb/defs.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ void handle_tx_ep0(void);
7878
/* USB Hardware */
7979
enum { EPT_CONTROL=0, EPT_ISO, EPT_BULK, EPT_INTERRUPT, EPT_DBLBUF };
8080
void usb_configure_ep(uint8_t ep, uint8_t type, uint32_t size);
81-
void usb_stall(uint8_t ep);
82-
void usb_clear_halt(uint8_t ep);
81+
void usb_stall(uint8_t epnr);
82+
void usb_clear_stall(uint8_t epnr);
8383
void usb_setaddr(uint8_t addr);
8484
void hw_usb_init(void);
8585
void hw_usb_deinit(void);
@@ -101,7 +101,7 @@ struct usb_driver {
101101
void (*read)(uint8_t epnr, void *buf, uint32_t len);
102102
void (*write)(uint8_t epnr, const void *buf, uint32_t len);
103103
void (*stall)(uint8_t epnr);
104-
void (*clear_halt)(uint8_t epnr);
104+
void (*clear_stall)(uint8_t epnr);
105105
};
106106

107107
extern const struct usb_driver dwc_otg;

src/usb/hw_at32f4.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ void usb_stall(uint8_t epnr)
8686
drv->stall(epnr);
8787
}
8888

89-
void usb_clear_halt(uint8_t epnr)
89+
void usb_clear_stall(uint8_t epnr)
9090
{
91-
drv->clear_halt(epnr);
91+
drv->clear_stall(epnr);
9292
}
9393

9494
void usb_configure_ep(uint8_t epnr, uint8_t type, uint32_t size)

src/usb/hw_dwc_otg.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -240,11 +240,16 @@ static void dwc_otg_write(uint8_t epnr, const void *buf, uint32_t len)
240240

241241
static void dwc_otg_stall(uint8_t epnr)
242242
{
243-
otg_diep[epnr].ctl |= OTG_DIEPCTL_STALL;
244-
otg_doep[epnr].ctl |= OTG_DOEPCTL_STALL;
243+
bool_t in = !!(epnr & 0x80);
244+
epnr &= 0x7f;
245+
if (in) {
246+
otg_diep[epnr].ctl |= OTG_DIEPCTL_STALL;
247+
} else {
248+
otg_doep[epnr].ctl |= OTG_DOEPCTL_STALL;
249+
}
245250
}
246251

247-
static void dwc_otg_clear_halt(uint8_t epnr)
252+
static void dwc_otg_clear_stall(uint8_t epnr)
248253
{
249254
bool_t in = !!(epnr & 0x80);
250255
epnr &= 0x7f;
@@ -490,7 +495,7 @@ const struct usb_driver dwc_otg = {
490495
.read = dwc_otg_read,
491496
.write = dwc_otg_write,
492497
.stall = dwc_otg_stall,
493-
.clear_halt = dwc_otg_clear_halt
498+
.clear_stall = dwc_otg_clear_stall
494499
};
495500

496501
/*

src/usb/hw_f1.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,9 @@ void usb_stall(uint8_t epnr)
5959
usbd.stall(epnr);
6060
}
6161

62-
void usb_clear_halt(uint8_t epnr)
62+
void usb_clear_stall(uint8_t epnr)
6363
{
64-
usbd.clear_halt(epnr);
64+
usbd.clear_stall(epnr);
6565
}
6666

6767
void usb_configure_ep(uint8_t epnr, uint8_t type, uint32_t size)

src/usb/hw_f7.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,9 @@ void usb_stall(uint8_t epnr)
148148
dwc_otg.stall(epnr);
149149
}
150150

151-
void usb_clear_halt(uint8_t epnr)
151+
void usb_clear_stall(uint8_t epnr)
152152
{
153-
dwc_otg.clear_halt(epnr);
153+
dwc_otg.clear_stall(epnr);
154154
}
155155

156156
void usb_configure_ep(uint8_t epnr, uint8_t type, uint32_t size)

src/usb/hw_usbd.c

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -182,30 +182,60 @@ static void usbd_write(uint8_t ep, const void *buf, uint32_t len)
182182
usb->epr[ep] = epr;
183183
}
184184

185-
static void usbd_stall(uint8_t ep)
185+
static void usbd_stall(uint8_t epnr)
186186
{
187-
uint16_t epr = usb->epr[ep];
188-
epr &= 0x073f;
189-
epr |= 0x8080;
190-
epr ^= USB_EPR_STAT_TX(USB_STAT_STALL);
191-
usb->epr[ep] = epr;
187+
bool_t in;
188+
uint16_t epr;
189+
190+
in = !!(epnr & 0x80);
191+
epnr &= 0x7f;
192+
epr = usb->epr[epnr];
193+
194+
if (in) {
195+
epr &= 0x073f;
196+
epr ^= USB_EPR_STAT_TX(USB_STAT_STALL);
197+
} else {
198+
epr &= 0x370f;
199+
epr ^= USB_EPR_STAT_RX(USB_STAT_STALL);
200+
}
201+
202+
epr |= 0x8080; /* preserve rc_w0 fields */
203+
usb->epr[epnr] = epr;
192204
}
193205

194-
static void usbd_clear_halt(uint8_t epnr)
206+
static void usbd_clear_stall(uint8_t epnr)
195207
{
196-
bool_t in = !!(epnr & 0x80);
197-
uint16_t epr, val;
208+
bool_t in, dbl_buf;
209+
uint16_t epr;
210+
int new_status = USB_STAT_VALID;
211+
212+
in = !!(epnr & 0x80);
198213
epnr &= 0x7f;
199214
epr = usb->epr[epnr];
200-
val = epr & 0x070f; /* preserve R/W: EA, EP_TYPE, EP_KIND */
201-
val |= 0x8080; /* preserve rc_w0: CTR_TX, CTR_RX */
202-
/* STAT written as 0: no toggle, unchanged.
203-
* Write current DTOG value to toggle it to 0 if set. */
204-
if (in)
205-
val |= epr & USB_EPR_DTOG_TX;
206-
else
207-
val |= epr & USB_EPR_DTOG_RX;
208-
usb->epr[epnr] = val;
215+
dbl_buf = !!(epr & USB_EPR_EP_KIND_DBL_BUF);
216+
217+
/* Clear data toggle and set status to VALID or NAK as appropriate. */
218+
if (in) {
219+
if (dbl_buf) {
220+
epr ^= 0x4000; /* Set SW_BUF */
221+
} else {
222+
epr &= ~0x4000;
223+
new_status = USB_STAT_NAK;
224+
}
225+
epr &= 0x477f; /* preserve rw & t, except tx toggle and status */
226+
epr ^= USB_EPR_STAT_TX(new_status);
227+
} else {
228+
if (dbl_buf) {
229+
epr |= 0x0040; /* Clear SW_BUF */
230+
} else {
231+
epr &= ~0x0040;
232+
}
233+
epr &= 0x774f; /* preserve rw & t, except rx toggle and status */
234+
epr ^= USB_EPR_STAT_RX(new_status);
235+
}
236+
237+
epr |= 0x8080; /* preserve rc_w0 fields */
238+
usb->epr[epnr] = epr;
209239
}
210240

211241
static void usbd_configure_ep(uint8_t ep, uint8_t type, uint32_t size)
@@ -411,7 +441,7 @@ const struct usb_driver usbd = {
411441
.read = usbd_read,
412442
.write = usbd_write,
413443
.stall = usbd_stall,
414-
.clear_halt = usbd_clear_halt
444+
.clear_stall = usbd_clear_stall
415445
};
416446

417447
/*

src/usb/hw_usbd_at32f4.c

Lines changed: 44 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -207,69 +207,60 @@ static void usbd_write(uint8_t epnr, const void *buf, uint32_t len)
207207
usb->epr[epnr] = epr;
208208
}
209209

210-
static void usbd_stall(uint8_t ep)
210+
static void usbd_stall(uint8_t epnr)
211211
{
212-
uint16_t epr = usb->epr[ep];
213-
epr &= 0x073f;
214-
epr |= 0x8080;
215-
epr ^= USB_EPR_STAT_TX(USB_STAT_STALL);
216-
usb->epr[ep] = epr;
212+
bool_t in;
213+
uint16_t epr;
214+
215+
in = !!(epnr & 0x80);
216+
epnr &= 0x7f;
217+
epr = usb->epr[epnr];
218+
epr |= 0x8080; /* preserve rc_w0 fields */
219+
220+
if (in) {
221+
epr &= 0x073f;
222+
epr ^= USB_EPR_STAT_TX(USB_STAT_STALL);
223+
} else {
224+
epr &= 0x370f;
225+
epr ^= USB_EPR_STAT_RX(USB_STAT_STALL);
226+
}
227+
228+
usb->epr[epnr] = epr;
217229
}
218230

219-
static void usbd_clear_halt(uint8_t epnr)
231+
static void usbd_clear_stall(uint8_t epnr)
220232
{
221-
bool_t in = !!(epnr & 0x80);
222-
struct ep *ep;
223-
volatile struct usb_bufd *bd;
224-
uint16_t old_epr, new_epr;
225-
uint32_t oldpri;
233+
bool_t in, dbl_buf;
234+
uint16_t epr;
235+
int new_status = USB_STAT_VALID;
226236

237+
in = !!(epnr & 0x80);
227238
epnr &= 0x7f;
228-
ep = &eps[epnr];
229-
bd = &usb_bufd[epnr];
230-
231-
old_epr = usb->epr[epnr];
232-
new_epr = old_epr & 0x070f; /* preserve rw & t fields */
233-
234-
if (ep->is_dblbuf) {
239+
epr = usb->epr[epnr];
240+
dbl_buf = !!(epr & USB_EPR_EP_KIND_DBL_BUF);
235241

236-
/* Reset double-buffer ring and endpoint state to match
237-
* usbd_configure_ep() initialisation. Buffer addresses
238-
* (bd->addr_0/1) are not changed. */
239-
oldpri = IRQ_save(USB_IRQ_PRI);
240-
ep->db.bufc = ep->db.bufp = ep->db.tx_hw_slots = 0;
241-
if (in) {
242-
bd->count_0 = bd->count_1 = 0;
243-
/* TX: Clears SW_BUF. */
244-
new_epr |= old_epr & 0x4000;
245-
/* TX: Clears data toggle and sets status to VALID. */
246-
new_epr |= (old_epr & 0x0070)
247-
^ USB_EPR_STAT_TX(USB_STAT_VALID);
248-
ep->db.kick = TRUE;
242+
/* Clear data toggle and set status to VALID or NAK as appropriate. */
243+
if (in) {
244+
if (dbl_buf) {
245+
epr ^= 0x4000; /* Set SW_BUF */
249246
} else {
250-
bd->count_0 = bd->count_1 = 0x8400; /* USB_FS_MPS */
251-
/* RX: Sets SW_BUF. */
252-
new_epr |= (old_epr & 0x0040) ^ 0x0040;
253-
ep->db.kick = FALSE;
254-
/* RX: Clears data toggle and sets status to VALID. */
255-
new_epr |= (old_epr & 0x7000)
256-
^ USB_EPR_STAT_RX(USB_STAT_VALID);
247+
epr &= ~0x4000;
248+
new_status = USB_STAT_NAK;
257249
}
258-
barrier();
259-
usb->epr[epnr] = new_epr;
260-
IRQ_restore(oldpri);
261-
250+
epr &= 0x477f; /* preserve rw & t, except tx toggle and status */
251+
epr ^= USB_EPR_STAT_TX(new_status);
262252
} else {
263-
264-
/* Standard endpoint: clear data toggle only. */
265-
new_epr |= 0x8080; /* preserve rc_w0 fields */
266-
if (in)
267-
new_epr |= old_epr & USB_EPR_DTOG_TX;
268-
else
269-
new_epr |= old_epr & USB_EPR_DTOG_RX;
270-
usb->epr[epnr] = new_epr;
271-
253+
if (dbl_buf) {
254+
epr |= 0x0040; /* Clear SW_BUF */
255+
} else {
256+
epr &= ~0x0040;
257+
}
258+
epr &= 0x774f; /* preserve rw & t, except rx toggle and status */
259+
epr ^= USB_EPR_STAT_RX(new_status);
272260
}
261+
262+
epr |= 0x8080; /* preserve rc_w0 fields */
263+
usb->epr[epnr] = epr;
273264
}
274265

275266
static void usbd_configure_ep(uint8_t epnr, uint8_t type, uint32_t size)
@@ -583,7 +574,7 @@ const struct usb_driver usbd = {
583574
.read = usbd_read,
584575
.write = usbd_write,
585576
.stall = usbd_stall,
586-
.clear_halt = usbd_clear_halt
577+
.clear_stall = usbd_clear_stall
587578
};
588579

589580
/*

0 commit comments

Comments
 (0)