libopencm3
A free/libre/open-source firmware library for various ARM Cortex-M3 microcontrollers.
usb_control.c
Go to the documentation of this file.
1/** @defgroup usb_control_file Generic USB Control Requests
2
3@ingroup USB
4
5@brief <b>Generic USB Control Requests</b>
6
7@version 1.0.0
8
9@author @htmlonly &copy; @endhtmlonly 2010
10Gareth McMullin <gareth@blacksphere.co.nz>
11
12@date 10 March 2013
13
14LGPL License Terms @ref lgpl_license
15*/
16
17/*
18 * This file is part of the libopencm3 project.
19 *
20 * Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
21 *
22 * This library is free software: you can redistribute it and/or modify
23 * it under the terms of the GNU Lesser General Public License as published by
24 * the Free Software Foundation, either version 3 of the License, or
25 * (at your option) any later version.
26 *
27 * This library is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU Lesser General Public License for more details.
31 *
32 * You should have received a copy of the GNU Lesser General Public License
33 * along with this library. If not, see <http://www.gnu.org/licenses/>.
34 */
35
36/**@{*/
37
38#include <stdlib.h>
39#include <libopencm3/usb/usbd.h>
40#include "usb_private.h"
41
42/*
43 * According to the USB 2.0 specification, section 8.5.3, when a control
44 * transfer is stalled, the pipe becomes idle. We provide one utility to stall
45 * a transaction to reduce boilerplate code.
46 */
47static void stall_transaction(usbd_device *usbd_dev)
48{
49 usbd_ep_stall_set(usbd_dev, 0, 1);
50 usbd_dev->control_state.state = IDLE;
51}
52
53/**
54 * If we're replying with _some_ data, but less than the host is expecting,
55 * then we normally just do a short transfer. But if it's short, but a
56 * multiple of the endpoint max packet size, we need an explicit ZLP.
57 * @param len how much data we want to transfer
58 * @param wLength how much the host asked for
59 * @param ep_size
60 * @return
61 */
62static bool needs_zlp(uint16_t len, uint16_t wLength, uint8_t ep_size)
63{
64 if (len < wLength) {
65 if (len && (len % ep_size == 0)) {
66 return true;
67 }
68 }
69 return false;
70}
71
72/* Register application callback function for handling USB control requests. */
73int usbd_register_control_callback(usbd_device *usbd_dev, uint8_t type,
74 uint8_t type_mask,
75 usbd_control_callback callback)
76{
77 int i;
78
79 for (i = 0; i < MAX_USER_CONTROL_CALLBACK; i++) {
80 if (usbd_dev->user_control_callback[i].cb) {
81 continue;
82 }
83
84 usbd_dev->user_control_callback[i].type = type;
85 usbd_dev->user_control_callback[i].type_mask = type_mask;
86 usbd_dev->user_control_callback[i].cb = callback;
87 return 0;
88 }
89
90 return -1;
91}
92
93static void usb_control_send_chunk(usbd_device *usbd_dev)
94{
95 if (usbd_dev->desc->bMaxPacketSize0 <
96 usbd_dev->control_state.ctrl_len) {
97 /* Data stage, normal transmission */
98 usbd_ep_write_packet(usbd_dev, 0,
99 usbd_dev->control_state.ctrl_buf,
100 usbd_dev->desc->bMaxPacketSize0);
101 usbd_dev->control_state.state = DATA_IN;
102 usbd_dev->control_state.ctrl_buf +=
103 usbd_dev->desc->bMaxPacketSize0;
104 usbd_dev->control_state.ctrl_len -=
105 usbd_dev->desc->bMaxPacketSize0;
106 } else {
107 /* Data stage, end of transmission */
108 usbd_ep_write_packet(usbd_dev, 0,
109 usbd_dev->control_state.ctrl_buf,
110 usbd_dev->control_state.ctrl_len);
111
112 usbd_dev->control_state.state =
113 usbd_dev->control_state.needs_zlp ?
114 DATA_IN : LAST_DATA_IN;
115 usbd_dev->control_state.needs_zlp = false;
116 usbd_dev->control_state.ctrl_len = 0;
117 usbd_dev->control_state.ctrl_buf = NULL;
118 }
119}
120
122{
123 uint16_t packetsize = MIN(usbd_dev->desc->bMaxPacketSize0,
124 usbd_dev->control_state.req.wLength -
125 usbd_dev->control_state.ctrl_len);
126 uint16_t size = usbd_ep_read_packet(usbd_dev, 0,
127 usbd_dev->control_state.ctrl_buf +
128 usbd_dev->control_state.ctrl_len,
129 packetsize);
130
131 if (size != packetsize) {
132 stall_transaction(usbd_dev);
133 return -1;
134 }
135
136 usbd_dev->control_state.ctrl_len += size;
137
138 return packetsize;
139}
140
143 struct usb_setup_data *req)
144{
145 int i, result = 0;
146 struct user_control_callback *cb = usbd_dev->user_control_callback;
147
148 /* Call user command hook function. */
149 for (i = 0; i < MAX_USER_CONTROL_CALLBACK; i++) {
150 if (cb[i].cb == NULL) {
151 break;
152 }
153
154 if ((req->bmRequestType & cb[i].type_mask) == cb[i].type) {
155 result = cb[i].cb(usbd_dev, req,
156 &(usbd_dev->control_state.ctrl_buf),
157 &(usbd_dev->control_state.ctrl_len),
158 &(usbd_dev->control_state.complete));
159 if (result == USBD_REQ_HANDLED ||
160 result == USBD_REQ_NOTSUPP) {
161 return result;
162 }
163 }
164 }
165
166 /* Try standard request if not already handled. */
167 return _usbd_standard_request(usbd_dev, req,
168 &(usbd_dev->control_state.ctrl_buf),
169 &(usbd_dev->control_state.ctrl_len));
170}
171
172/* Handle commands and read requests. */
174 struct usb_setup_data *req)
175{
176 usbd_dev->control_state.ctrl_buf = usbd_dev->ctrl_buf;
177 usbd_dev->control_state.ctrl_len = req->wLength;
178
179 if (usb_control_request_dispatch(usbd_dev, req)) {
180 if (req->wLength) {
181 usbd_dev->control_state.needs_zlp =
182 needs_zlp(usbd_dev->control_state.ctrl_len,
183 req->wLength,
184 usbd_dev->desc->bMaxPacketSize0);
185 /* Go to data out stage if handled. */
186 usb_control_send_chunk(usbd_dev);
187 } else {
188 /* Go to status stage if handled. */
189 usbd_ep_write_packet(usbd_dev, 0, NULL, 0);
190 usbd_dev->control_state.state = STATUS_IN;
191 }
192 } else {
193 /* Stall endpoint on failure. */
194 stall_transaction(usbd_dev);
195 }
196}
197
199 struct usb_setup_data *req)
200{
201 if (req->wLength > usbd_dev->ctrl_buf_len) {
202 stall_transaction(usbd_dev);
203 return;
204 }
205
206 /* Buffer into which to write received data. */
207 usbd_dev->control_state.ctrl_buf = usbd_dev->ctrl_buf;
208 usbd_dev->control_state.ctrl_len = 0;
209 /* Wait for DATA OUT stage. */
210 if (req->wLength > usbd_dev->desc->bMaxPacketSize0) {
211 usbd_dev->control_state.state = DATA_OUT;
212 } else {
213 usbd_dev->control_state.state = LAST_DATA_OUT;
214 }
215
216 usbd_ep_nak_set(usbd_dev, 0, 0);
217}
218
219/* Do not appear to belong to the API, so are omitted from docs */
220/**@}*/
221
222void _usbd_control_setup(usbd_device *usbd_dev, uint8_t ea)
223{
224 struct usb_setup_data *req = &usbd_dev->control_state.req;
225 (void)ea;
226
227 usbd_dev->control_state.complete = NULL;
228
229 usbd_ep_nak_set(usbd_dev, 0, 1);
230
231 if (req->wLength == 0) {
232 usb_control_setup_read(usbd_dev, req);
233 } else if (req->bmRequestType & 0x80) {
234 usb_control_setup_read(usbd_dev, req);
235 } else {
236 usb_control_setup_write(usbd_dev, req);
237 }
238}
239
240void _usbd_control_out(usbd_device *usbd_dev, uint8_t ea)
241{
242 (void)ea;
243
244 switch (usbd_dev->control_state.state) {
245 case DATA_OUT:
246 if (usb_control_recv_chunk(usbd_dev) < 0) {
247 break;
248 }
249 if ((usbd_dev->control_state.req.wLength -
250 usbd_dev->control_state.ctrl_len) <=
251 usbd_dev->desc->bMaxPacketSize0) {
252 usbd_dev->control_state.state = LAST_DATA_OUT;
253 }
254 break;
255 case LAST_DATA_OUT:
256 if (usb_control_recv_chunk(usbd_dev) < 0) {
257 break;
258 }
259 /*
260 * We have now received the full data payload.
261 * Invoke callback to process.
262 */
263 if (usb_control_request_dispatch(usbd_dev,
264 &(usbd_dev->control_state.req))) {
265 /* Go to status stage on success. */
266 usbd_ep_write_packet(usbd_dev, 0, NULL, 0);
267 usbd_dev->control_state.state = STATUS_IN;
268 } else {
269 stall_transaction(usbd_dev);
270 }
271 break;
272 case STATUS_OUT:
273 usbd_ep_read_packet(usbd_dev, 0, NULL, 0);
274 usbd_dev->control_state.state = IDLE;
275 if (usbd_dev->control_state.complete) {
276 usbd_dev->control_state.complete(usbd_dev,
277 &(usbd_dev->control_state.req));
278 }
279 usbd_dev->control_state.complete = NULL;
280 break;
281 default:
282 stall_transaction(usbd_dev);
283 }
284}
285
286void _usbd_control_in(usbd_device *usbd_dev, uint8_t ea)
287{
288 (void)ea;
289 struct usb_setup_data *req = &(usbd_dev->control_state.req);
290
291 switch (usbd_dev->control_state.state) {
292 case DATA_IN:
293 usb_control_send_chunk(usbd_dev);
294 break;
295 case LAST_DATA_IN:
296 usbd_dev->control_state.state = STATUS_OUT;
297 usbd_ep_nak_set(usbd_dev, 0, 0);
298 break;
299 case STATUS_IN:
300 if (usbd_dev->control_state.complete) {
301 usbd_dev->control_state.complete(usbd_dev,
302 &(usbd_dev->control_state.req));
303 }
304
305 /* Exception: Handle SET ADDRESS function here... */
306 if ((req->bmRequestType == 0) &&
307 (req->bRequest == USB_REQ_SET_ADDRESS)) {
308 usbd_dev->driver->set_address(usbd_dev, req->wValue);
309 }
310 usbd_dev->control_state.state = IDLE;
311 break;
312 default:
313 stall_transaction(usbd_dev);
314 }
315}
316
static void usb_control_setup_read(usbd_device *usbd_dev, struct usb_setup_data *req)
Definition: usb_control.c:173
static bool needs_zlp(uint16_t len, uint16_t wLength, uint8_t ep_size)
If we're replying with some data, but less than the host is expecting, then we normally just do a sho...
Definition: usb_control.c:62
static void usb_control_send_chunk(usbd_device *usbd_dev)
Definition: usb_control.c:93
int usbd_register_control_callback(usbd_device *usbd_dev, uint8_t type, uint8_t type_mask, usbd_control_callback callback)
Registers a control callback.
Definition: usb_control.c:73
static void usb_control_setup_write(usbd_device *usbd_dev, struct usb_setup_data *req)
Definition: usb_control.c:198
static enum usbd_request_return_codes usb_control_request_dispatch(usbd_device *usbd_dev, struct usb_setup_data *req)
Definition: usb_control.c:142
static int usb_control_recv_chunk(usbd_device *usbd_dev)
Definition: usb_control.c:121
static void stall_transaction(usbd_device *usbd_dev)
Definition: usb_control.c:47
void usbd_ep_nak_set(usbd_device *usbd_dev, uint8_t addr, uint8_t nak)
Set an Out endpoint to NAK.
Definition: usb.c:168
struct _usbd_device usbd_device
Definition: usbd.h:53
void usbd_ep_stall_set(usbd_device *usbd_dev, uint8_t addr, uint8_t stall)
Set/clear STALL condition on an endpoint.
Definition: usb.c:158
uint16_t usbd_ep_write_packet(usbd_device *usbd_dev, uint8_t addr, const void *buf, uint16_t len)
Write a packet.
Definition: usb.c:146
uint16_t usbd_ep_read_packet(usbd_device *usbd_dev, uint8_t addr, void *buf, uint16_t len)
Read a packet.
Definition: usb.c:152
enum usbd_request_return_codes(* usbd_control_callback)(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete)
Definition: usbd.h:120
usbd_request_return_codes
Definition: usbd.h:46
@ USBD_REQ_HANDLED
Definition: usbd.h:48
@ USBD_REQ_NOTSUPP
Definition: usbd.h:47
#define USB_REQ_SET_ADDRESS
Definition: usbstd.h:90
uint8_t bRequest
Definition: usbstd.h:58
uint8_t bmRequestType
Definition: usbstd.h:57
uint16_t wValue
Definition: usbstd.h:59
uint16_t wLength
Definition: usbstd.h:61
void _usbd_control_out(usbd_device *usbd_dev, uint8_t ea)
Definition: usb_control.c:240
void _usbd_control_in(usbd_device *usbd_dev, uint8_t ea)
Definition: usb_control.c:286
void _usbd_control_setup(usbd_device *usbd_dev, uint8_t ea)
Definition: usb_control.c:222
enum usbd_request_return_codes _usbd_standard_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len)
Definition: usb_standard.c:616