summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/usb-api.md144
-rw-r--r--firmware/drivers/isp1583.c2
-rw-r--r--firmware/drivers/m66591.c2
-rw-r--r--firmware/drivers/usb-designware.c2
-rw-r--r--firmware/export/usb_core.h4
-rw-r--r--firmware/export/usb_drv.h8
-rw-r--r--firmware/target/arm/as3525/usb-drv-as3525.c4
-rw-r--r--firmware/target/arm/rk27xx/usb-drv-rk27xx.c2
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/tnetv105_usb_drv.c2
-rw-r--r--firmware/target/arm/usb-drv-arc.c2
-rw-r--r--firmware/target/arm/usb-s3c6400x.c2
-rw-r--r--firmware/target/arm/usb-tcc.c2
-rw-r--r--firmware/target/mips/ingenic_jz47xx/usb-jz4740.c2
-rw-r--r--firmware/target/mips/ingenic_jz47xx/usb-jz4760.c2
-rw-r--r--firmware/usbstack/usb_core.c2
15 files changed, 168 insertions, 14 deletions
diff --git a/docs/usb-api.md b/docs/usb-api.md
new file mode 100644
index 0000000000..a21d6fd703
--- /dev/null
+++ b/docs/usb-api.md
@@ -0,0 +1,144 @@
1Handling USB control requests
2=============================
3
4API 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
18The two `usb_core` functions are common to all targets with a USB stack and
19are implemented in `usb_core.c`. The USB driver calls them to inform the core
20when a control request arrives or is completed.
21
22Each USB driver implements `usb_drv_control_response()`. The core calls this
23to 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
29The old control request API is available through this function. Drivers which
30don't yet implement the new API can use the legacy API instead. To support
31legacy drivers, the USB core implements all functions in the new API and
32emulates the old control request handling behavior, bugs included.
33
34This is intended as a stopgap measure so that old drivers keep working as-is.
35The core can start using the new API right away, and drivers can be ported
36one-by-one as time allows. Once all drivers are ported to the new API, all
37legacy driver support can be removed.
38
39Request handling process
40------------------------
41
42The driver submits control requests to the USB core one at a time. Once a
43request is submitted, it must be completed before the next request can be
44submitted. This mirrors normal USB operation.
45
46When the USB driver receives a setup packet from the host, it submits it
47to the core to begin handling the control transfer. The driver calls
48`usb_core_control_request(req, NULL)`, passing the setup packet in `req`.
49The second argument, `reqdata`, is not used at this time and is passed
50as `NULL`.
51
52The core processes the setup packet and calls `usb_drv_control_response()`
53when it's done. The allowed responses depend on the type of control transfer
54being 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
73The driver calls `usb_core_control_request()` twice to handle control writes.
74The first call allows the core to handle the setup packet, and if the core
75decides to accept the data phase, the second call is made when the data has
76been received without error.
77
78#### Setup phase
79
80The first call is made at the end of the setup phase, after receiving the
81setup packet. The driver passes `reqdata = NULL` to indicate this.
82
83The 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
92If the core accepts the data phase, the driver will re-submit the request
93when the data phase is completed correctly. If any error occurs during the
94data phase, the driver will not re-submit the request; instead, it will
95call `usb_core_control_complete()` with a non-zero status code.
96
97#### Status phase
98
99The second call to `usb_core_control_request()` is made at the end of the data
100phase. The `reqdata` passed by the driver is the same one that the core passed
101in its `USB_CONTROL_RECEIVE` response.
102
103The 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
110The 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
112completed successfully; a non-zero code means it failed. Note that failure
113can occur even if the request was successful from the core's perspective.
114
115If the core response is `USB_CONTROL_STALL` at any point, the request is
116considered complete. In this case, the driver won't deliver a completion
117notification because it would be redundant.
118
119The driver may only complete a request after the core has provided a response
120to any pending `usb_core_control_request()` call. Specifically, if the core
121has not yet responded to a request, the driver needs to defer the completion
122notification until it sees the core's response. If the core's response is a
123stall, 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.
diff --git a/firmware/drivers/isp1583.c b/firmware/drivers/isp1583.c
index 18a4e9c720..e60339d9fc 100644
--- a/firmware/drivers/isp1583.c
+++ b/firmware/drivers/isp1583.c
@@ -341,7 +341,7 @@ static void usb_handle_setup_rx(void)
341 if (len == 8) 341 if (len == 8)
342 { 342 {
343 ISP1583_DFLOW_CTRLFUN |= DFLOW_CTRLFUN_STATUS; /* Acknowledge packet */ 343 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);
345 } 345 }
346 else 346 else
347 { 347 {
diff --git a/firmware/drivers/m66591.c b/firmware/drivers/m66591.c
index 5da1908290..822585d882 100644
--- a/firmware/drivers/m66591.c
+++ b/firmware/drivers/m66591.c
@@ -208,7 +208,7 @@ static void control_received(void) {
208 /* acknowledge packet recieved (clear valid) */ 208 /* acknowledge packet recieved (clear valid) */
209 M66591_INTSTAT_MAIN &= ~(1<<3); 209 M66591_INTSTAT_MAIN &= ~(1<<3);
210 210
211 usb_core_control_request(&temp); 211 usb_core_legacy_control_request(&temp);
212} 212}
213 213
214/* This is a helper function, it is used to notife the stack that a transfer is 214/* This is a helper function, it is used to notife the stack that a transfer is
diff --git a/firmware/drivers/usb-designware.c b/firmware/drivers/usb-designware.c
index ab4c6037b5..58b6a75180 100644
--- a/firmware/drivers/usb-designware.c
+++ b/firmware/drivers/usb-designware.c
@@ -741,7 +741,7 @@ static void usb_dw_handle_setup_received(void)
741 && (usb_ctrlsetup.bRequest == USB_REQ_SET_ADDRESS)) 741 && (usb_ctrlsetup.bRequest == USB_REQ_SET_ADDRESS))
742 usb_dw_set_address(usb_ctrlsetup.wValue); 742 usb_dw_set_address(usb_ctrlsetup.wValue);
743 743
744 usb_core_control_request(&usb_ctrlsetup); 744 usb_core_legacy_control_request(&usb_ctrlsetup);
745} 745}
746 746
747static void usb_dw_abort_endpoint(int epnum, enum usb_dw_epdir epdir) 747static void usb_dw_abort_endpoint(int epnum, enum usb_dw_epdir epdir)
diff --git a/firmware/export/usb_core.h b/firmware/export/usb_core.h
index 78a80435e1..fe1f7459cf 100644
--- a/firmware/export/usb_core.h
+++ b/firmware/export/usb_core.h
@@ -51,7 +51,9 @@ struct usb_class_driver;
51 51
52void usb_core_init(void); 52void usb_core_init(void);
53void usb_core_exit(void); 53void usb_core_exit(void);
54void usb_core_control_request(struct usb_ctrlrequest* req); 54void usb_core_control_request(struct usb_ctrlrequest* req, void* data);
55void usb_core_control_complete(int status);
56void usb_core_legacy_control_request(struct usb_ctrlrequest* req);
55void usb_core_transfer_complete(int endpoint,int dir,int status,int length); 57void usb_core_transfer_complete(int endpoint,int dir,int status,int length);
56void usb_core_bus_reset(void); 58void usb_core_bus_reset(void);
57bool usb_core_any_exclusive_storage(void); 59bool usb_core_any_exclusive_storage(void);
diff --git a/firmware/export/usb_drv.h b/firmware/export/usb_drv.h
index 01535c2786..3ef4db3c9c 100644
--- a/firmware/export/usb_drv.h
+++ b/firmware/export/usb_drv.h
@@ -56,6 +56,12 @@
56 * -> usb_drv_int_enable(false) [ditto] 56 * -> usb_drv_int_enable(false) [ditto]
57 * -> soc specific controller/clock deinit */ 57 * -> soc specific controller/clock deinit */
58 58
59enum usb_control_response {
60 USB_CONTROL_ACK,
61 USB_CONTROL_STALL,
62 USB_CONTROL_RECEIVE,
63};
64
59/* one-time initialisation of the USB driver */ 65/* one-time initialisation of the USB driver */
60void usb_drv_startup(void); 66void usb_drv_startup(void);
61void usb_drv_int_enable(bool enable); /* Target implemented */ 67void usb_drv_int_enable(bool enable); /* Target implemented */
@@ -69,6 +75,8 @@ bool usb_drv_stalled(int endpoint,bool in);
69int usb_drv_send(int endpoint, void* ptr, int length); 75int usb_drv_send(int endpoint, void* ptr, int length);
70int usb_drv_send_nonblocking(int endpoint, void* ptr, int length); 76int usb_drv_send_nonblocking(int endpoint, void* ptr, int length);
71int usb_drv_recv_nonblocking(int endpoint, void* ptr, int length); 77int usb_drv_recv_nonblocking(int endpoint, void* ptr, int length);
78void usb_drv_control_response(enum usb_control_response resp,
79 void* data, int length);
72void usb_drv_set_address(int address); 80void usb_drv_set_address(int address);
73void usb_drv_reset_endpoint(int endpoint, bool send); 81void usb_drv_reset_endpoint(int endpoint, bool send);
74bool usb_drv_powered(void); 82bool usb_drv_powered(void);
diff --git a/firmware/target/arm/as3525/usb-drv-as3525.c b/firmware/target/arm/as3525/usb-drv-as3525.c
index 8369edc400..d0875ed48c 100644
--- a/firmware/target/arm/as3525/usb-drv-as3525.c
+++ b/firmware/target/arm/as3525/usb-drv-as3525.c
@@ -655,7 +655,7 @@ static void handle_out_ep(int ep)
655 req->wIndex, 655 req->wIndex,
656 req->wLength); 656 req->wLength);
657 657
658 usb_core_control_request(&req_copy); 658 usb_core_legacy_control_request(&req_copy);
659 setup_desc_init(setup_desc); 659 setup_desc_init(setup_desc);
660 660
661 ep_sts &= ~USB_EP_STAT_SETUP_RCVD; 661 ep_sts &= ~USB_EP_STAT_SETUP_RCVD;
@@ -760,7 +760,7 @@ void INT_USB_FUNC(void)
760 got_set_configuration = 1; 760 got_set_configuration = 1;
761 761
762 set_config.wValue = USB_DEV_STS & USB_DEV_STS_MASK_CFG; 762 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);
764 intr &= ~USB_DEV_INTR_SET_CONFIG; 764 intr &= ~USB_DEV_INTR_SET_CONFIG;
765 } 765 }
766 if (intr & USB_DEV_INTR_EARLY_SUSPEND) {/* idle >3ms detected */ 766 if (intr & USB_DEV_INTR_EARLY_SUSPEND) {/* idle >3ms detected */
diff --git a/firmware/target/arm/rk27xx/usb-drv-rk27xx.c b/firmware/target/arm/rk27xx/usb-drv-rk27xx.c
index aac271c47a..77860b5494 100644
--- a/firmware/target/arm/rk27xx/usb-drv-rk27xx.c
+++ b/firmware/target/arm/rk27xx/usb-drv-rk27xx.c
@@ -117,7 +117,7 @@ static void setup_received(void)
117 setup_data[1] = SETUP2; 117 setup_data[1] = SETUP2;
118 118
119 /* pass setup data to the upper layer */ 119 /* 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);
121} 121}
122 122
123static int max_pkt_size(struct endpoint_t *endp) 123static int max_pkt_size(struct endpoint_t *endp)
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/tnetv105_usb_drv.c b/firmware/target/arm/tms320dm320/sansa-connect/tnetv105_usb_drv.c
index f1acc9c964..e5a9000f40 100644
--- a/firmware/target/arm/tms320dm320/sansa-connect/tnetv105_usb_drv.c
+++ b/firmware/target/arm/tms320dm320/sansa-connect/tnetv105_usb_drv.c
@@ -1181,7 +1181,7 @@ void VLYNQ(void)
1181 } 1181 }
1182 1182
1183 /* Process control packet */ 1183 /* Process control packet */
1184 usb_core_control_request(&setup); 1184 usb_core_legacy_control_request(&setup);
1185 } 1185 }
1186 1186
1187 if (sysIntrStatus.f.ep0_in_ack) 1187 if (sysIntrStatus.f.ep0_in_ack)
diff --git a/firmware/target/arm/usb-drv-arc.c b/firmware/target/arm/usb-drv-arc.c
index 4c53108f12..22751f27f0 100644
--- a/firmware/target/arm/usb-drv-arc.c
+++ b/firmware/target/arm/usb-drv-arc.c
@@ -877,7 +877,7 @@ static void control_received(void)
877 } 877 }
878 } 878 }
879 879
880 usb_core_control_request((struct usb_ctrlrequest*)tmp); 880 usb_core_legacy_control_request((struct usb_ctrlrequest*)tmp);
881} 881}
882 882
883static void transfer_completed(void) 883static void transfer_completed(void)
diff --git a/firmware/target/arm/usb-s3c6400x.c b/firmware/target/arm/usb-s3c6400x.c
index 71d04e6f2a..0f3ecf8c00 100644
--- a/firmware/target/arm/usb-s3c6400x.c
+++ b/firmware/target/arm/usb-s3c6400x.c
@@ -522,7 +522,7 @@ static void handle_ep_int(int ep, bool out)
522 ep0_setup_pkt->bRequest == USB_REQ_SET_ADDRESS) 522 ep0_setup_pkt->bRequest == USB_REQ_SET_ADDRESS)
523 DCFG = (DCFG & ~bitm(DCFG, devadr)) | (ep0_setup_pkt->wValue << DCFG_devadr_bitp); 523 DCFG = (DCFG & ~bitm(DCFG, devadr)) | (ep0_setup_pkt->wValue << DCFG_devadr_bitp);
524 524
525 usb_core_control_request(ep0_setup_pkt); 525 usb_core_legacy_control_request(ep0_setup_pkt);
526 } 526 }
527 } 527 }
528 528
diff --git a/firmware/target/arm/usb-tcc.c b/firmware/target/arm/usb-tcc.c
index 8ce75b6764..53f101c471 100644
--- a/firmware/target/arm/usb-tcc.c
+++ b/firmware/target/arm/usb-tcc.c
@@ -251,7 +251,7 @@ void handle_control(void)
251 DEBUG(2, "req: %02x %02d", req->bRequestType, req->bRequest); 251 DEBUG(2, "req: %02x %02d", req->bRequestType, req->bRequest);
252 } 252 }
253 253
254 usb_core_control_request(req); 254 usb_core_legacy_control_request(req);
255} 255}
256 256
257static 257static
diff --git a/firmware/target/mips/ingenic_jz47xx/usb-jz4740.c b/firmware/target/mips/ingenic_jz47xx/usb-jz4740.c
index 8d04c54a68..07d24be380 100644
--- a/firmware/target/mips/ingenic_jz47xx/usb-jz4740.c
+++ b/firmware/target/mips/ingenic_jz47xx/usb-jz4740.c
@@ -239,7 +239,7 @@ static void EP0_handler(void)
239 { 239 {
240 readFIFO(ep_recv, REG_USB_REG_COUNT0); 240 readFIFO(ep_recv, REG_USB_REG_COUNT0);
241 REG_USB_REG_CSR0 = csr0 | USB_CSR0_SVDOUTPKTRDY; /* clear OUTPKTRDY bit */ 241 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);
243 } 243 }
244} 244}
245 245
diff --git a/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c b/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c
index 5dbf9455e3..6db4a25d5c 100644
--- a/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c
+++ b/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c
@@ -335,7 +335,7 @@ static void EP0_handler(void)
335 ep0_data_requested = true; 335 ep0_data_requested = true;
336 else ep0_data_supplied = true; 336 else ep0_data_supplied = true;
337 REG_USB_CSR0 = csr0; 337 REG_USB_CSR0 = csr0;
338 usb_core_control_request(&ep0_rx.request); 338 usb_core_legacy_control_request(&ep0_rx.request);
339 ep_transfer_completed(ep_recv); 339 ep_transfer_completed(ep_recv);
340 } 340 }
341 } 341 }
diff --git a/firmware/usbstack/usb_core.c b/firmware/usbstack/usb_core.c
index 50d93f7561..1f17872ba8 100644
--- a/firmware/usbstack/usb_core.c
+++ b/firmware/usbstack/usb_core.c
@@ -977,7 +977,7 @@ void usb_core_handle_notify(long id, intptr_t data)
977} 977}
978 978
979/* called by usb_drv_int() */ 979/* called by usb_drv_int() */
980void usb_core_control_request(struct usb_ctrlrequest* req) 980void usb_core_legacy_control_request(struct usb_ctrlrequest* req)
981{ 981{
982 struct usb_transfer_completion_event_data* completion_event = 982 struct usb_transfer_completion_event_data* completion_event =
983 &ep_data[EP_CONTROL].completion_event[EP_DIR(USB_DIR_IN)]; 983 &ep_data[EP_CONTROL].completion_event[EP_DIR(USB_DIR_IN)];