Skip to content

Commit ec164c3

Browse files
committed
usb: introduce new control request API
Change-Id: I6545d8985ab683c026f28f6a7c0e23b40d0a6506
1 parent 71cc1e7 commit ec164c3

File tree

15 files changed

+168
-14
lines changed

15 files changed

+168
-14
lines changed

docs/usb-api.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
Handling USB control requests
2+
=============================
3+
4+
API overview
5+
------------
6+
7+
enum usb_control_response {
8+
USB_CONTROL_ACK,
9+
USB_CONTROL_STALL,
10+
USB_CONTROL_RECEIVE,
11+
};
12+
13+
void usb_core_control_request(struct usb_ctrlrequest* req, void* reqdata);
14+
void usb_core_control_complete(int status);
15+
void usb_drv_control_response(enum usb_control_response resp,
16+
void* data, int length);
17+
18+
The two `usb_core` functions are common to all targets with a USB stack and
19+
are implemented in `usb_core.c`. The USB driver calls them to inform the core
20+
when a control request arrives or is completed.
21+
22+
Each USB driver implements `usb_drv_control_response()`. The core calls this
23+
to let the driver know how to respond to each control request.
24+
25+
### Legacy API
26+
27+
void usb_core_legacy_control_request(struct usb_ctrlrequest* req);
28+
29+
The old control request API is available through this function. Drivers which
30+
don't yet implement the new API can use the legacy API instead. To support
31+
legacy drivers, the USB core implements all functions in the new API and
32+
emulates the old control request handling behavior, bugs included.
33+
34+
This is intended as a stopgap measure so that old drivers keep working as-is.
35+
The core can start using the new API right away, and drivers can be ported
36+
one-by-one as time allows. Once all drivers are ported to the new API, all
37+
legacy driver support can be removed.
38+
39+
Request handling process
40+
------------------------
41+
42+
The driver submits control requests to the USB core one at a time. Once a
43+
request is submitted, it must be completed before the next request can be
44+
submitted. This mirrors normal USB operation.
45+
46+
When the USB driver receives a setup packet from the host, it submits it
47+
to the core to begin handling the control transfer. The driver calls
48+
`usb_core_control_request(req, NULL)`, passing the setup packet in `req`.
49+
The second argument, `reqdata`, is not used at this time and is passed
50+
as `NULL`.
51+
52+
The core processes the setup packet and calls `usb_drv_control_response()`
53+
when it's done. The allowed responses depend on the type of control transfer
54+
being processed.
55+
56+
### Non-data transfers
57+
58+
- `USB_CONTROL_ACK`, to indicate the request was processed successfully.
59+
- `USB_CONTROL_STALL`, if the request is unsupported or cannot be processed.
60+
61+
### Control read transfers
62+
63+
- `USB_CONTROL_ACK`, to indicate the request was processed successfully.
64+
The core must provide a valid `data` buffer with `length` not exceeding
65+
the `wLength` field in the setup packet; otherwise, driver behavior is
66+
undefined. The driver will transfer this data to the host during the
67+
data phase of the control transfer, and then acknowledge the host's OUT
68+
packet to complete the transfer successfully.
69+
- `USB_CONTROL_STALL`, if the request is unsupported or cannot be processed.
70+
71+
### Control write transfers
72+
73+
The driver calls `usb_core_control_request()` twice to handle control writes.
74+
The first call allows the core to handle the setup packet, and if the core
75+
decides to accept the data phase, the second call is made when the data has
76+
been received without error.
77+
78+
#### Setup phase
79+
80+
The first call is made at the end of the setup phase, after receiving the
81+
setup packet. The driver passes `reqdata = NULL` to indicate this.
82+
83+
The core can decide whether it wants to receive the data phase:
84+
85+
- `USB_CONTROL_RECEIVE`, if the core wishes to continue to the data phase.
86+
The core must provide a valid `data` buffer with `length` greater than or
87+
equal to the `wLength` specified in the setup packet; otherwise, driver
88+
behavior is undefined. The driver will proceed to the data phase and store
89+
received data into the provided buffer.
90+
- `USB_CONTROL_STALL`, if the request is unsupported or cannot be processed.
91+
92+
If the core accepts the data phase, the driver will re-submit the request
93+
when the data phase is completed correctly. If any error occurs during the
94+
data phase, the driver will not re-submit the request; instead, it will
95+
call `usb_core_control_complete()` with a non-zero status code.
96+
97+
#### Status phase
98+
99+
The second call to `usb_core_control_request()` is made at the end of the data
100+
phase. The `reqdata` passed by the driver is the same one that the core passed
101+
in its `USB_CONTROL_RECEIVE` response.
102+
103+
The core's allowed responses are:
104+
105+
- `USB_CONTROL_ACK`, to indicate the request was processed successfully.
106+
- `USB_CONTROL_STALL`, if the request is unsupported or cannot be processed.
107+
108+
### Request completion
109+
110+
The driver will notify the core when a request has completed by calling
111+
`usb_core_control_complete()`. A status code of zero means the request was
112+
completed successfully; a non-zero code means it failed. Note that failure
113+
can occur even if the request was successful from the core's perspective.
114+
115+
If the core response is `USB_CONTROL_STALL` at any point, the request is
116+
considered complete. In this case, the driver won't deliver a completion
117+
notification because it would be redundant.
118+
119+
The driver may only complete a request after the core has provided a response
120+
to any pending `usb_core_control_request()` call. Specifically, if the core
121+
has not yet responded to a request, the driver needs to defer the completion
122+
notification until it sees the core's response. If the core's response is a
123+
stall, then the notification should be silently dropped.
124+
125+
### Notes
126+
127+
- Driver behavior is undefined if the core makes an inappropriate response
128+
to a request, for example, responding with `USB_CONTROL_ACK` in the setup
129+
phase of a control write or `USB_CONTROL_RECEIVE` to a non-data request.
130+
The only permissible responses are the documented ones.
131+
132+
- If a response requires a buffer, then `data` must be non-NULL unless the
133+
`length` is also zero. If a buffer is not required, the core must pass
134+
`data = NULL` and `length = 0`. Otherwise, driver behavior is undefined.
135+
There are two responses which require a buffer:
136+
+ `USB_CONTROL_ACK` to a control read
137+
+ `USB_CONTROL_RECEIVE` to the setup phase of a control write
138+
139+
- Drivers must be prepared to accept a setup packet at any time, including
140+
in the middle of a control request. In such a case, devices are required
141+
to abort the ongoing request and start handling the new request. (This is
142+
intended as an error recovery mechanism and should not be abused by hosts
143+
in normal operation.) The driver must take care to notify the core of the
144+
current request's failure, and then submit the new request.

firmware/drivers/isp1583.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ static void usb_handle_setup_rx(void)
341341
if (len == 8)
342342
{
343343
ISP1583_DFLOW_CTRLFUN |= DFLOW_CTRLFUN_STATUS; /* Acknowledge packet */
344-
usb_core_control_request((struct usb_ctrlrequest*)setup_pkt_buf);
344+
usb_core_legacy_control_request((struct usb_ctrlrequest*)setup_pkt_buf);
345345
}
346346
else
347347
{

firmware/drivers/m66591.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ static void control_received(void) {
208208
/* acknowledge packet recieved (clear valid) */
209209
M66591_INTSTAT_MAIN &= ~(1<<3);
210210

211-
usb_core_control_request(&temp);
211+
usb_core_legacy_control_request(&temp);
212212
}
213213

214214
/* This is a helper function, it is used to notife the stack that a transfer is

firmware/drivers/usb-designware.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -741,7 +741,7 @@ static void usb_dw_handle_setup_received(void)
741741
&& (usb_ctrlsetup.bRequest == USB_REQ_SET_ADDRESS))
742742
usb_dw_set_address(usb_ctrlsetup.wValue);
743743

744-
usb_core_control_request(&usb_ctrlsetup);
744+
usb_core_legacy_control_request(&usb_ctrlsetup);
745745
}
746746

747747
static void usb_dw_abort_endpoint(int epnum, enum usb_dw_epdir epdir)

firmware/export/usb_core.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ struct usb_class_driver;
5151

5252
void usb_core_init(void);
5353
void usb_core_exit(void);
54-
void usb_core_control_request(struct usb_ctrlrequest* req);
54+
void usb_core_control_request(struct usb_ctrlrequest* req, void* data);
55+
void usb_core_control_complete(int status);
56+
void usb_core_legacy_control_request(struct usb_ctrlrequest* req);
5557
void usb_core_transfer_complete(int endpoint,int dir,int status,int length);
5658
void usb_core_bus_reset(void);
5759
bool usb_core_any_exclusive_storage(void);

firmware/export/usb_drv.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@
5656
* -> usb_drv_int_enable(false) [ditto]
5757
* -> soc specific controller/clock deinit */
5858

59+
enum usb_control_response {
60+
USB_CONTROL_ACK,
61+
USB_CONTROL_STALL,
62+
USB_CONTROL_RECEIVE,
63+
};
64+
5965
/* one-time initialisation of the USB driver */
6066
void usb_drv_startup(void);
6167
void usb_drv_int_enable(bool enable); /* Target implemented */
@@ -69,6 +75,8 @@ bool usb_drv_stalled(int endpoint,bool in);
6975
int usb_drv_send(int endpoint, void* ptr, int length);
7076
int usb_drv_send_nonblocking(int endpoint, void* ptr, int length);
7177
int usb_drv_recv_nonblocking(int endpoint, void* ptr, int length);
78+
void usb_drv_control_response(enum usb_control_response resp,
79+
void* data, int length);
7280
void usb_drv_set_address(int address);
7381
void usb_drv_reset_endpoint(int endpoint, bool send);
7482
bool usb_drv_powered(void);

firmware/target/arm/as3525/usb-drv-as3525.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ static void handle_out_ep(int ep)
655655
req->wIndex,
656656
req->wLength);
657657

658-
usb_core_control_request(&req_copy);
658+
usb_core_legacy_control_request(&req_copy);
659659
setup_desc_init(setup_desc);
660660

661661
ep_sts &= ~USB_EP_STAT_SETUP_RCVD;
@@ -760,7 +760,7 @@ void INT_USB_FUNC(void)
760760
got_set_configuration = 1;
761761

762762
set_config.wValue = USB_DEV_STS & USB_DEV_STS_MASK_CFG;
763-
usb_core_control_request(&set_config);
763+
usb_core_legacy_control_request(&set_config);
764764
intr &= ~USB_DEV_INTR_SET_CONFIG;
765765
}
766766
if (intr & USB_DEV_INTR_EARLY_SUSPEND) {/* idle >3ms detected */

firmware/target/arm/rk27xx/usb-drv-rk27xx.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ static void setup_received(void)
117117
setup_data[1] = SETUP2;
118118

119119
/* pass setup data to the upper layer */
120-
usb_core_control_request((struct usb_ctrlrequest*)setup_data);
120+
usb_core_legacy_control_request((struct usb_ctrlrequest*)setup_data);
121121
}
122122

123123
static int max_pkt_size(struct endpoint_t *endp)

firmware/target/arm/tms320dm320/sansa-connect/tnetv105_usb_drv.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1181,7 +1181,7 @@ void VLYNQ(void)
11811181
}
11821182

11831183
/* Process control packet */
1184-
usb_core_control_request(&setup);
1184+
usb_core_legacy_control_request(&setup);
11851185
}
11861186

11871187
if (sysIntrStatus.f.ep0_in_ack)

firmware/target/arm/usb-drv-arc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -877,7 +877,7 @@ static void control_received(void)
877877
}
878878
}
879879

880-
usb_core_control_request((struct usb_ctrlrequest*)tmp);
880+
usb_core_legacy_control_request((struct usb_ctrlrequest*)tmp);
881881
}
882882

883883
static void transfer_completed(void)

firmware/target/arm/usb-s3c6400x.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ static void handle_ep_int(int ep, bool out)
522522
ep0_setup_pkt->bRequest == USB_REQ_SET_ADDRESS)
523523
DCFG = (DCFG & ~bitm(DCFG, devadr)) | (ep0_setup_pkt->wValue << DCFG_devadr_bitp);
524524

525-
usb_core_control_request(ep0_setup_pkt);
525+
usb_core_legacy_control_request(ep0_setup_pkt);
526526
}
527527
}
528528

firmware/target/arm/usb-tcc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ void handle_control(void)
251251
DEBUG(2, "req: %02x %02d", req->bRequestType, req->bRequest);
252252
}
253253

254-
usb_core_control_request(req);
254+
usb_core_legacy_control_request(req);
255255
}
256256

257257
static

firmware/target/mips/ingenic_jz47xx/usb-jz4740.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ static void EP0_handler(void)
239239
{
240240
readFIFO(ep_recv, REG_USB_REG_COUNT0);
241241
REG_USB_REG_CSR0 = csr0 | USB_CSR0_SVDOUTPKTRDY; /* clear OUTPKTRDY bit */
242-
usb_core_control_request((struct usb_ctrlrequest*)ep_recv->buf);
242+
usb_core_legacy_control_request((struct usb_ctrlrequest*)ep_recv->buf);
243243
}
244244
}
245245

firmware/target/mips/ingenic_jz47xx/usb-jz4760.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ static void EP0_handler(void)
335335
ep0_data_requested = true;
336336
else ep0_data_supplied = true;
337337
REG_USB_CSR0 = csr0;
338-
usb_core_control_request(&ep0_rx.request);
338+
usb_core_legacy_control_request(&ep0_rx.request);
339339
ep_transfer_completed(ep_recv);
340340
}
341341
}

firmware/usbstack/usb_core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -977,7 +977,7 @@ void usb_core_handle_notify(long id, intptr_t data)
977977
}
978978

979979
/* called by usb_drv_int() */
980-
void usb_core_control_request(struct usb_ctrlrequest* req)
980+
void usb_core_legacy_control_request(struct usb_ctrlrequest* req)
981981
{
982982
struct usb_transfer_completion_event_data* completion_event =
983983
&ep_data[EP_CONTROL].completion_event[EP_DIR(USB_DIR_IN)];

0 commit comments

Comments
 (0)