aboutsummaryrefslogtreecommitdiff
path: root/src/usb/setup.c
blob: 609267a9148763ece42445265109fcc46185e73a (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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <stdlib.h>

#include "CH58x_common.h"

#include "utils.h"

uint8_t *cfg_desc;

// FIXME: here wasting 1KiB of ram
void (*if_handlers[256])(USB_SETUP_REQ *request);
void (*ep_handlers[7])();

/* Configuration Descriptor template */
USB_CFG_DESCR cfg_static = {
	.bLength = sizeof(USB_CFG_DESCR),
	.bDescriptorType = 0x02,
	.wTotalLength = sizeof(USB_CFG_DESCR), // will be updated on cfg_desc_add()
	.bNumInterfaces = 0, // will be updated on cfg_desc_add()
	.bConfigurationValue = 0x01,
	.iConfiguration = 4,
	.bmAttributes = 0xA0,
	.MaxPower = 50 // mA
};

void cfg_desc_append(void *desc)
{
	uint8_t cfg_len = 0;
	uint8_t len = ((uint8_t *)desc)[0];
	if (cfg_desc) // attempting to add a non-Configuration Descriptor
		cfg_len = ((USB_CFG_DESCR *)cfg_desc)->wTotalLength;
	uint8_t newlen = cfg_len + len;

	cfg_desc = realloc(cfg_desc, newlen); // TODO: add a safe check here

	memcpy(cfg_desc + cfg_len, desc, len);

	((USB_CFG_DESCR *)cfg_desc)->wTotalLength = newlen;
	((USB_CFG_DESCR *)cfg_desc)->bNumInterfaces += ((uint8_t *)desc)[1] == 0x04;
}

int ep_cb_register(int ep_num, void (*cb)())
{
	if (ep_num > 8)
		return -1;
	if (ep_handlers[ep_num]) // already registerd
		return -1;

	ep_handlers[ep_num] = cb;
	return 0;
}

int if_cb_register(uint8_t if_num, void (*cb)(USB_SETUP_REQ *request))
{
	if (if_handlers[if_num]) // already registered
		return -1;

	if_handlers[if_num] = cb;
	return 0;
}

void dma_register(uint8_t ep_num, void *buf)
{
	if (ep_num > 7) // CH582 support only 8 endpoint
		return;

	volatile uint16_t *p_regs[] = {
		&R16_UEP0_DMA,
		&R16_UEP1_DMA,
		&R16_UEP2_DMA,
		&R16_UEP3_DMA,
		NULL,
		&R16_UEP5_DMA,
		&R16_UEP6_DMA,
		&R16_UEP7_DMA,
	};
	volatile uint8_t *ctrl_regs[] = {
		&R8_UEP0_CTRL,
		&R8_UEP1_CTRL,
		&R8_UEP2_CTRL,
		&R8_UEP3_CTRL,
		&R8_UEP4_CTRL,
		&R8_UEP5_CTRL,
		&R8_UEP6_CTRL,
		&R8_UEP7_CTRL,
	};
	// ep4's dma buffer is hardcoded pointing to 
	// the next ep0
	if (ep_num != 4)
		*p_regs[ep_num] = (uint16_t)(uint32_t)buf;

	*ctrl_regs[ep_num] = UEP_R_RES_ACK | UEP_T_RES_NAK;
}

static void init(void)
{
	R8_USB_CTRL = 0x00;

	R8_UEP4_1_MOD = RB_UEP4_RX_EN | RB_UEP4_TX_EN |
				RB_UEP1_RX_EN | RB_UEP1_TX_EN;
	R8_UEP2_3_MOD = RB_UEP2_RX_EN | RB_UEP2_TX_EN |
				RB_UEP3_RX_EN | RB_UEP3_TX_EN;
	R8_UEP567_MOD = RB_UEP7_RX_EN | RB_UEP7_TX_EN |
				RB_UEP6_RX_EN | RB_UEP6_TX_EN |
				RB_UEP5_RX_EN | RB_UEP5_TX_EN;

	R16_PIN_ANALOG_IE |= RB_PIN_USB_IE | RB_PIN_USB_DP_PU;
	R8_UDEV_CTRL = RB_UD_PD_DIS | RB_UD_PORT_EN;

	R8_USB_DEV_AD = 0x00;
	R8_USB_INT_FG = 0xFF;
	R8_USB_CTRL = RB_UC_DEV_PU_EN | RB_UC_INT_BUSY | RB_UC_DMA_EN;
	R8_USB_INT_EN = RB_UIE_SUSPEND | RB_UIE_BUS_RST | RB_UIE_TRANSFER;
}

void ctrl_init();
void hiddev_init();
void cdc_acm_init();

void usb_start() {
	cfg_desc_append(&cfg_static);

	ctrl_init();

	/* This should be placed first, the python script always looks
	for the first interface (not the interface number) */
	hiddev_init();

	init();
	PFIC_EnableIRQ(USB_IRQn);
}