summaryrefslogtreecommitdiff
path: root/chip/stm32/usb_dfu_runtime.c
blob: 7626faec8eb6cb412ebc2bd8143b4c9bbffeee07 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/* Copyright 2022 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "dfu_bootmanager_shared.h"
#include "registers.h"
#include "usb_descriptor.h"
#include "usb_dfu_runtime.h"
#include "usb_hw.h"

/* DFU Run-Time Descriptor Set. */
const struct usb_interface_descriptor USB_IFACE_DESC(USB_IFACE_DFU) = {
	.bLength = USB_DT_INTERFACE_SIZE,
	.bDescriptorType = USB_DT_INTERFACE,
	.bInterfaceNumber = USB_IFACE_DFU,
	.bAlternateSetting = 0,
	.bNumEndpoints = 0,
	.bInterfaceClass = USB_CLASS_APP_SPEC,
	.bInterfaceSubClass = USB_DFU_RUNTIME_SUBCLASS,
	.bInterfaceProtocol = USB_DFU_RUNTIME_PROTOCOL,
	.iInterface = USB_STR_DFU_NAME,
};

/* DFU Functional Descriptor. */
const struct usb_runtime_dfu_functional_desc USB_CUSTOM_DESC_VAR(USB_IFACE_DFU,
						dfu, dfu_func_desc) = {
	.bLength = USB_DFU_RUNTIME_DESC_SIZE,
	.bDescriptorType = USB_DFU_RUNTIME_DESC_FUNCTIONAL,
	.bmAttributes = USB_DFU_RUNTIME_DESC_ATTRS,
	.wDetachTimeOut = USB_DFU_RUNTIME_DESC_DETACH_TIMEOUT,
	.wTransferSize = USB_DFU_RUNTIME_DESC_TRANSFER_SIZE,
	.bcdDFUVersion = USB_DFU_RUNTIME_DESC_DFU_VERSION,
};

static int dfu_runtime_request(usb_uint *ep0_buf_rx, usb_uint *ep0_buf_tx)
{
	struct usb_setup_packet packet;

	usb_read_setup_packet(ep0_buf_rx, &packet);
	btable_ep[0].tx_count = 0;
	if ((packet.bmRequestType ==
		(USB_DIR_OUT | USB_TYPE_STANDARD |  USB_RECIP_INTERFACE)) &&
		(packet.bRequest == USB_REQ_SET_INTERFACE)) {
		/* ACK the change alternative mode request. */

		STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, 0);
		return 0;
	} else if ((packet.bmRequestType ==
			(USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) &&
			(packet.bRequest == USB_DFU_RUNTIME_REQ_DETACH)) {
		/* Host is requesting a jump from application to DFU mode. */

		STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, 0);
		return dfu_bootmanager_enter_dfu();
	} else if (packet.bmRequestType ==
			(USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) {
		if (packet.bRequest == USB_DFU_RUNTIME_REQ_GET_STATUS) {
			/* Return the Get Status response. */

			struct usb_runtime_dfu_get_status_resp response = {
				.bStatus = USB_DFU_RUNTIME_STATUS_OK,
				.bState = USB_DFU_RUNTIME_STATE_APP_IDLE,
			};

			memcpy_to_usbram((void *) usb_sram_addr(ep0_buf_tx),
				&response, sizeof(response));
			btable_ep[0].tx_count = sizeof(response);
			STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, 0);
			return 0;
		}
		if (packet.bRequest == USB_DFU_RUNTIME_REQ_GET_STATE) {
			/* Return the Get State response. */

			struct usb_runtime_dfu_get_state_resp response = {
				.bState = USB_DFU_RUNTIME_STATE_APP_IDLE,
			};

			memcpy_to_usbram((void *) usb_sram_addr(ep0_buf_tx),
				&response, sizeof(response));
			btable_ep[0].tx_count = sizeof(response);
			STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, 0);
			return 0;
		}
	}
	/* Return a stall response for any unhandled packets. */

	STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_RX_VALID | EP_TX_STALL, 0);
	return 0;
}

USB_DECLARE_IFACE(USB_IFACE_DFU, dfu_runtime_request)