xref: /rk3399_ARM-atf/drivers/usb/usb_device.c (revision 859bfd8d42341c6dea2b193db79dc4828e074ad7)
1*859bfd8dSPatrick Delaunay /*
2*859bfd8dSPatrick Delaunay  * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
3*859bfd8dSPatrick Delaunay  *
4*859bfd8dSPatrick Delaunay  * SPDX-License-Identifier: BSD-3-Clause
5*859bfd8dSPatrick Delaunay  */
6*859bfd8dSPatrick Delaunay 
7*859bfd8dSPatrick Delaunay #include <assert.h>
8*859bfd8dSPatrick Delaunay #include <stdint.h>
9*859bfd8dSPatrick Delaunay 
10*859bfd8dSPatrick Delaunay #include <common/debug.h>
11*859bfd8dSPatrick Delaunay #include <drivers/usb_device.h>
12*859bfd8dSPatrick Delaunay 
13*859bfd8dSPatrick Delaunay /* Define for EP address */
14*859bfd8dSPatrick Delaunay #define EP_DIR_MASK		BIT(7)
15*859bfd8dSPatrick Delaunay #define EP_DIR_IN		BIT(7)
16*859bfd8dSPatrick Delaunay #define EP_NUM_MASK		GENMASK(3, 0)
17*859bfd8dSPatrick Delaunay 
18*859bfd8dSPatrick Delaunay #define EP0_IN			(0U | EP_DIR_IN)
19*859bfd8dSPatrick Delaunay #define EP0_OUT			0U
20*859bfd8dSPatrick Delaunay 
21*859bfd8dSPatrick Delaunay /* USB address between 1 through 127 = 0x7F mask */
22*859bfd8dSPatrick Delaunay #define ADDRESS_MASK		GENMASK(6, 0)
23*859bfd8dSPatrick Delaunay 
24*859bfd8dSPatrick Delaunay /*
25*859bfd8dSPatrick Delaunay  * Set a STALL condition over an endpoint
26*859bfd8dSPatrick Delaunay  * pdev: USB handle
27*859bfd8dSPatrick Delaunay  * ep_addr: endpoint address
28*859bfd8dSPatrick Delaunay  * return : status
29*859bfd8dSPatrick Delaunay  */
30*859bfd8dSPatrick Delaunay static enum usb_status usb_core_set_stall(struct usb_handle *pdev, uint8_t ep_addr)
31*859bfd8dSPatrick Delaunay {
32*859bfd8dSPatrick Delaunay 	struct usbd_ep *ep;
33*859bfd8dSPatrick Delaunay 	struct pcd_handle *hpcd = (struct pcd_handle *)pdev->data;
34*859bfd8dSPatrick Delaunay 	uint8_t num;
35*859bfd8dSPatrick Delaunay 
36*859bfd8dSPatrick Delaunay 	num = ep_addr & EP_NUM_MASK;
37*859bfd8dSPatrick Delaunay 	if (num >= USBD_EP_NB) {
38*859bfd8dSPatrick Delaunay 		return USBD_FAIL;
39*859bfd8dSPatrick Delaunay 	}
40*859bfd8dSPatrick Delaunay 	if ((EP_DIR_MASK & ep_addr) == EP_DIR_IN) {
41*859bfd8dSPatrick Delaunay 		ep = &hpcd->in_ep[num];
42*859bfd8dSPatrick Delaunay 		ep->is_in = true;
43*859bfd8dSPatrick Delaunay 	} else {
44*859bfd8dSPatrick Delaunay 		ep = &hpcd->out_ep[num];
45*859bfd8dSPatrick Delaunay 		ep->is_in = false;
46*859bfd8dSPatrick Delaunay 	}
47*859bfd8dSPatrick Delaunay 	ep->num = num;
48*859bfd8dSPatrick Delaunay 
49*859bfd8dSPatrick Delaunay 	pdev->driver->ep_set_stall(hpcd->instance, ep);
50*859bfd8dSPatrick Delaunay 	if (num == 0U) {
51*859bfd8dSPatrick Delaunay 		pdev->driver->ep0_out_start(hpcd->instance);
52*859bfd8dSPatrick Delaunay 	}
53*859bfd8dSPatrick Delaunay 
54*859bfd8dSPatrick Delaunay 	return USBD_OK;
55*859bfd8dSPatrick Delaunay }
56*859bfd8dSPatrick Delaunay 
57*859bfd8dSPatrick Delaunay /*
58*859bfd8dSPatrick Delaunay  * usb_core_get_desc
59*859bfd8dSPatrick Delaunay  *         Handle Get Descriptor requests
60*859bfd8dSPatrick Delaunay  * pdev : device instance
61*859bfd8dSPatrick Delaunay  * req : usb request
62*859bfd8dSPatrick Delaunay  */
63*859bfd8dSPatrick Delaunay static void usb_core_get_desc(struct usb_handle *pdev, struct usb_setup_req *req)
64*859bfd8dSPatrick Delaunay {
65*859bfd8dSPatrick Delaunay 	uint16_t len;
66*859bfd8dSPatrick Delaunay 	uint8_t *pbuf;
67*859bfd8dSPatrick Delaunay 	uint8_t desc_type = HIBYTE(req->value);
68*859bfd8dSPatrick Delaunay 	uint8_t desc_idx = LOBYTE(req->value);
69*859bfd8dSPatrick Delaunay 
70*859bfd8dSPatrick Delaunay 	switch (desc_type) {
71*859bfd8dSPatrick Delaunay 	case USB_DESC_TYPE_DEVICE:
72*859bfd8dSPatrick Delaunay 		pbuf = pdev->desc->get_device_desc(&len);
73*859bfd8dSPatrick Delaunay 		break;
74*859bfd8dSPatrick Delaunay 
75*859bfd8dSPatrick Delaunay 	case USB_DESC_TYPE_CONFIGURATION:
76*859bfd8dSPatrick Delaunay 		pbuf = (uint8_t *)pdev->desc->get_config_desc(&len);
77*859bfd8dSPatrick Delaunay 		pbuf[1] = USB_DESC_TYPE_CONFIGURATION;
78*859bfd8dSPatrick Delaunay 		break;
79*859bfd8dSPatrick Delaunay 
80*859bfd8dSPatrick Delaunay 	case USB_DESC_TYPE_STRING:
81*859bfd8dSPatrick Delaunay 		switch (desc_idx) {
82*859bfd8dSPatrick Delaunay 		case USBD_IDX_LANGID_STR:
83*859bfd8dSPatrick Delaunay 			pbuf = pdev->desc->get_lang_id_desc(&len);
84*859bfd8dSPatrick Delaunay 			break;
85*859bfd8dSPatrick Delaunay 
86*859bfd8dSPatrick Delaunay 		case USBD_IDX_MFC_STR:
87*859bfd8dSPatrick Delaunay 			pbuf = pdev->desc->get_manufacturer_desc(&len);
88*859bfd8dSPatrick Delaunay 			break;
89*859bfd8dSPatrick Delaunay 
90*859bfd8dSPatrick Delaunay 		case USBD_IDX_PRODUCT_STR:
91*859bfd8dSPatrick Delaunay 			pbuf = pdev->desc->get_product_desc(&len);
92*859bfd8dSPatrick Delaunay 			break;
93*859bfd8dSPatrick Delaunay 
94*859bfd8dSPatrick Delaunay 		case USBD_IDX_SERIAL_STR:
95*859bfd8dSPatrick Delaunay 			pbuf = pdev->desc->get_serial_desc(&len);
96*859bfd8dSPatrick Delaunay 			break;
97*859bfd8dSPatrick Delaunay 
98*859bfd8dSPatrick Delaunay 		case USBD_IDX_CONFIG_STR:
99*859bfd8dSPatrick Delaunay 			pbuf = pdev->desc->get_configuration_desc(&len);
100*859bfd8dSPatrick Delaunay 			break;
101*859bfd8dSPatrick Delaunay 
102*859bfd8dSPatrick Delaunay 		case USBD_IDX_INTERFACE_STR:
103*859bfd8dSPatrick Delaunay 			pbuf = pdev->desc->get_interface_desc(&len);
104*859bfd8dSPatrick Delaunay 			break;
105*859bfd8dSPatrick Delaunay 
106*859bfd8dSPatrick Delaunay 		/* For all USER string */
107*859bfd8dSPatrick Delaunay 		case USBD_IDX_USER0_STR:
108*859bfd8dSPatrick Delaunay 		default:
109*859bfd8dSPatrick Delaunay 			pbuf = pdev->desc->get_usr_desc(desc_idx - USBD_IDX_USER0_STR, &len);
110*859bfd8dSPatrick Delaunay 			break;
111*859bfd8dSPatrick Delaunay 		}
112*859bfd8dSPatrick Delaunay 		break;
113*859bfd8dSPatrick Delaunay 
114*859bfd8dSPatrick Delaunay 	case USB_DESC_TYPE_DEVICE_QUALIFIER:
115*859bfd8dSPatrick Delaunay 		pbuf = (uint8_t *)pdev->desc->get_device_qualifier_desc(&len);
116*859bfd8dSPatrick Delaunay 		break;
117*859bfd8dSPatrick Delaunay 
118*859bfd8dSPatrick Delaunay 	case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION:
119*859bfd8dSPatrick Delaunay 		pbuf = (uint8_t *)pdev->desc->get_config_desc(&len);
120*859bfd8dSPatrick Delaunay 		pbuf[1] = USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION;
121*859bfd8dSPatrick Delaunay 		break;
122*859bfd8dSPatrick Delaunay 
123*859bfd8dSPatrick Delaunay 	default:
124*859bfd8dSPatrick Delaunay 		ERROR("Unknown request %i\n", desc_type);
125*859bfd8dSPatrick Delaunay 		usb_core_ctl_error(pdev);
126*859bfd8dSPatrick Delaunay 		return;
127*859bfd8dSPatrick Delaunay 	}
128*859bfd8dSPatrick Delaunay 
129*859bfd8dSPatrick Delaunay 	if ((len != 0U) && (req->length != 0U)) {
130*859bfd8dSPatrick Delaunay 		len = MIN(len, req->length);
131*859bfd8dSPatrick Delaunay 
132*859bfd8dSPatrick Delaunay 		/* Start the transfer */
133*859bfd8dSPatrick Delaunay 		usb_core_transmit_ep0(pdev, pbuf, len);
134*859bfd8dSPatrick Delaunay 	}
135*859bfd8dSPatrick Delaunay }
136*859bfd8dSPatrick Delaunay 
137*859bfd8dSPatrick Delaunay /*
138*859bfd8dSPatrick Delaunay  * usb_core_set_config
139*859bfd8dSPatrick Delaunay  *         Handle Set device configuration request
140*859bfd8dSPatrick Delaunay  * pdev : device instance
141*859bfd8dSPatrick Delaunay  * req : usb request
142*859bfd8dSPatrick Delaunay  */
143*859bfd8dSPatrick Delaunay static void usb_core_set_config(struct usb_handle *pdev, struct usb_setup_req *req)
144*859bfd8dSPatrick Delaunay {
145*859bfd8dSPatrick Delaunay 	static uint8_t cfgidx;
146*859bfd8dSPatrick Delaunay 
147*859bfd8dSPatrick Delaunay 	cfgidx = LOBYTE(req->value);
148*859bfd8dSPatrick Delaunay 
149*859bfd8dSPatrick Delaunay 	if (cfgidx > USBD_MAX_NUM_CONFIGURATION) {
150*859bfd8dSPatrick Delaunay 		usb_core_ctl_error(pdev);
151*859bfd8dSPatrick Delaunay 		return;
152*859bfd8dSPatrick Delaunay 	}
153*859bfd8dSPatrick Delaunay 
154*859bfd8dSPatrick Delaunay 	switch (pdev->dev_state) {
155*859bfd8dSPatrick Delaunay 	case USBD_STATE_ADDRESSED:
156*859bfd8dSPatrick Delaunay 		if (cfgidx != 0U) {
157*859bfd8dSPatrick Delaunay 			pdev->dev_config = cfgidx;
158*859bfd8dSPatrick Delaunay 			pdev->dev_state = USBD_STATE_CONFIGURED;
159*859bfd8dSPatrick Delaunay 			if (!pdev->class) {
160*859bfd8dSPatrick Delaunay 				usb_core_ctl_error(pdev);
161*859bfd8dSPatrick Delaunay 				return;
162*859bfd8dSPatrick Delaunay 			}
163*859bfd8dSPatrick Delaunay 			/* Set configuration and Start the Class */
164*859bfd8dSPatrick Delaunay 			if (pdev->class->init(pdev, cfgidx) != 0U) {
165*859bfd8dSPatrick Delaunay 				usb_core_ctl_error(pdev);
166*859bfd8dSPatrick Delaunay 				return;
167*859bfd8dSPatrick Delaunay 			}
168*859bfd8dSPatrick Delaunay 		}
169*859bfd8dSPatrick Delaunay 		break;
170*859bfd8dSPatrick Delaunay 
171*859bfd8dSPatrick Delaunay 	case USBD_STATE_CONFIGURED:
172*859bfd8dSPatrick Delaunay 		if (cfgidx == 0U) {
173*859bfd8dSPatrick Delaunay 			pdev->dev_state = USBD_STATE_ADDRESSED;
174*859bfd8dSPatrick Delaunay 			pdev->dev_config = cfgidx;
175*859bfd8dSPatrick Delaunay 			pdev->class->de_init(pdev, cfgidx);
176*859bfd8dSPatrick Delaunay 		} else if (cfgidx != pdev->dev_config) {
177*859bfd8dSPatrick Delaunay 			if (pdev->class != NULL) {
178*859bfd8dSPatrick Delaunay 				usb_core_ctl_error(pdev);
179*859bfd8dSPatrick Delaunay 				return;
180*859bfd8dSPatrick Delaunay 			}
181*859bfd8dSPatrick Delaunay 			/* Clear old configuration */
182*859bfd8dSPatrick Delaunay 			pdev->class->de_init(pdev, pdev->dev_config);
183*859bfd8dSPatrick Delaunay 			/* Set new configuration */
184*859bfd8dSPatrick Delaunay 			pdev->dev_config = cfgidx;
185*859bfd8dSPatrick Delaunay 			/* Set configuration and start the USB class */
186*859bfd8dSPatrick Delaunay 			if (pdev->class->init(pdev, cfgidx) != 0U) {
187*859bfd8dSPatrick Delaunay 				usb_core_ctl_error(pdev);
188*859bfd8dSPatrick Delaunay 				return;
189*859bfd8dSPatrick Delaunay 			}
190*859bfd8dSPatrick Delaunay 		}
191*859bfd8dSPatrick Delaunay 		break;
192*859bfd8dSPatrick Delaunay 
193*859bfd8dSPatrick Delaunay 	default:
194*859bfd8dSPatrick Delaunay 		usb_core_ctl_error(pdev);
195*859bfd8dSPatrick Delaunay 		return;
196*859bfd8dSPatrick Delaunay 	}
197*859bfd8dSPatrick Delaunay 
198*859bfd8dSPatrick Delaunay 	/* Send status */
199*859bfd8dSPatrick Delaunay 	usb_core_transmit_ep0(pdev, NULL, 0U);
200*859bfd8dSPatrick Delaunay }
201*859bfd8dSPatrick Delaunay 
202*859bfd8dSPatrick Delaunay /*
203*859bfd8dSPatrick Delaunay  * usb_core_get_status
204*859bfd8dSPatrick Delaunay  *         Handle Get Status request
205*859bfd8dSPatrick Delaunay  * pdev : device instance
206*859bfd8dSPatrick Delaunay  * req : usb request
207*859bfd8dSPatrick Delaunay  */
208*859bfd8dSPatrick Delaunay static void usb_core_get_status(struct usb_handle *pdev,
209*859bfd8dSPatrick Delaunay 				struct usb_setup_req *req)
210*859bfd8dSPatrick Delaunay {
211*859bfd8dSPatrick Delaunay 	if ((pdev->dev_state != USBD_STATE_ADDRESSED) &&
212*859bfd8dSPatrick Delaunay 	    (pdev->dev_state != USBD_STATE_CONFIGURED)) {
213*859bfd8dSPatrick Delaunay 		usb_core_ctl_error(pdev);
214*859bfd8dSPatrick Delaunay 		return;
215*859bfd8dSPatrick Delaunay 	}
216*859bfd8dSPatrick Delaunay 
217*859bfd8dSPatrick Delaunay 	pdev->dev_config_status = USB_CONFIG_SELF_POWERED;
218*859bfd8dSPatrick Delaunay 
219*859bfd8dSPatrick Delaunay 	if (pdev->dev_remote_wakeup != 0U) {
220*859bfd8dSPatrick Delaunay 		pdev->dev_config_status |= USB_CONFIG_REMOTE_WAKEUP;
221*859bfd8dSPatrick Delaunay 	}
222*859bfd8dSPatrick Delaunay 
223*859bfd8dSPatrick Delaunay 	/* Start the transfer */
224*859bfd8dSPatrick Delaunay 	usb_core_transmit_ep0(pdev, (uint8_t *)&pdev->dev_config_status, 2U);
225*859bfd8dSPatrick Delaunay }
226*859bfd8dSPatrick Delaunay 
227*859bfd8dSPatrick Delaunay /*
228*859bfd8dSPatrick Delaunay  * usb_core_set_address
229*859bfd8dSPatrick Delaunay  *         Set device address
230*859bfd8dSPatrick Delaunay  * pdev : device instance
231*859bfd8dSPatrick Delaunay  * req : usb request
232*859bfd8dSPatrick Delaunay  */
233*859bfd8dSPatrick Delaunay static void usb_core_set_address(struct usb_handle *pdev,
234*859bfd8dSPatrick Delaunay 				 struct usb_setup_req *req)
235*859bfd8dSPatrick Delaunay {
236*859bfd8dSPatrick Delaunay 	uint8_t dev_addr;
237*859bfd8dSPatrick Delaunay 
238*859bfd8dSPatrick Delaunay 	if ((req->index != 0U) || (req->length != 0U)) {
239*859bfd8dSPatrick Delaunay 		usb_core_ctl_error(pdev);
240*859bfd8dSPatrick Delaunay 		return;
241*859bfd8dSPatrick Delaunay 	}
242*859bfd8dSPatrick Delaunay 
243*859bfd8dSPatrick Delaunay 	dev_addr = req->value & ADDRESS_MASK;
244*859bfd8dSPatrick Delaunay 	if (pdev->dev_state != USBD_STATE_DEFAULT) {
245*859bfd8dSPatrick Delaunay 		usb_core_ctl_error(pdev);
246*859bfd8dSPatrick Delaunay 		return;
247*859bfd8dSPatrick Delaunay 	}
248*859bfd8dSPatrick Delaunay 
249*859bfd8dSPatrick Delaunay 	pdev->dev_address = dev_addr;
250*859bfd8dSPatrick Delaunay 	pdev->driver->set_address(((struct pcd_handle *)(pdev->data))->instance, dev_addr);
251*859bfd8dSPatrick Delaunay 
252*859bfd8dSPatrick Delaunay 	/* Send status */
253*859bfd8dSPatrick Delaunay 	usb_core_transmit_ep0(pdev, NULL, 0U);
254*859bfd8dSPatrick Delaunay 
255*859bfd8dSPatrick Delaunay 	if (dev_addr != 0U) {
256*859bfd8dSPatrick Delaunay 		pdev->dev_state  = USBD_STATE_ADDRESSED;
257*859bfd8dSPatrick Delaunay 	} else {
258*859bfd8dSPatrick Delaunay 		pdev->dev_state  = USBD_STATE_DEFAULT;
259*859bfd8dSPatrick Delaunay 	}
260*859bfd8dSPatrick Delaunay }
261*859bfd8dSPatrick Delaunay 
262*859bfd8dSPatrick Delaunay /*
263*859bfd8dSPatrick Delaunay  * usb_core_dev_req
264*859bfd8dSPatrick Delaunay  *         Handle standard usb device requests
265*859bfd8dSPatrick Delaunay  * pdev : device instance
266*859bfd8dSPatrick Delaunay  * req : usb request
267*859bfd8dSPatrick Delaunay  * return : status
268*859bfd8dSPatrick Delaunay  */
269*859bfd8dSPatrick Delaunay static enum usb_status usb_core_dev_req(struct usb_handle *pdev,
270*859bfd8dSPatrick Delaunay 					struct usb_setup_req *req)
271*859bfd8dSPatrick Delaunay {
272*859bfd8dSPatrick Delaunay 	VERBOSE("receive request %i\n", req->b_request);
273*859bfd8dSPatrick Delaunay 	switch (req->b_request) {
274*859bfd8dSPatrick Delaunay 	case USB_REQ_GET_DESCRIPTOR:
275*859bfd8dSPatrick Delaunay 		usb_core_get_desc(pdev, req);
276*859bfd8dSPatrick Delaunay 		break;
277*859bfd8dSPatrick Delaunay 
278*859bfd8dSPatrick Delaunay 	case USB_REQ_SET_CONFIGURATION:
279*859bfd8dSPatrick Delaunay 		usb_core_set_config(pdev, req);
280*859bfd8dSPatrick Delaunay 		break;
281*859bfd8dSPatrick Delaunay 
282*859bfd8dSPatrick Delaunay 	case USB_REQ_GET_STATUS:
283*859bfd8dSPatrick Delaunay 		usb_core_get_status(pdev, req);
284*859bfd8dSPatrick Delaunay 		break;
285*859bfd8dSPatrick Delaunay 
286*859bfd8dSPatrick Delaunay 	case USB_REQ_SET_ADDRESS:
287*859bfd8dSPatrick Delaunay 		usb_core_set_address(pdev, req);
288*859bfd8dSPatrick Delaunay 		break;
289*859bfd8dSPatrick Delaunay 
290*859bfd8dSPatrick Delaunay 	case USB_REQ_GET_CONFIGURATION:
291*859bfd8dSPatrick Delaunay 	case USB_REQ_SET_FEATURE:
292*859bfd8dSPatrick Delaunay 	case USB_REQ_CLEAR_FEATURE:
293*859bfd8dSPatrick Delaunay 	default:
294*859bfd8dSPatrick Delaunay 		ERROR("NOT SUPPORTED %i\n", req->b_request);
295*859bfd8dSPatrick Delaunay 		usb_core_ctl_error(pdev);
296*859bfd8dSPatrick Delaunay 		break;
297*859bfd8dSPatrick Delaunay 	}
298*859bfd8dSPatrick Delaunay 
299*859bfd8dSPatrick Delaunay 	return USBD_OK;
300*859bfd8dSPatrick Delaunay }
301*859bfd8dSPatrick Delaunay 
302*859bfd8dSPatrick Delaunay /*
303*859bfd8dSPatrick Delaunay  * usb_core_itf_req
304*859bfd8dSPatrick Delaunay  *         Handle standard usb interface requests
305*859bfd8dSPatrick Delaunay  * pdev : device instance
306*859bfd8dSPatrick Delaunay  * req : usb request
307*859bfd8dSPatrick Delaunay  * return : status
308*859bfd8dSPatrick Delaunay  */
309*859bfd8dSPatrick Delaunay static enum usb_status usb_core_itf_req(struct usb_handle *pdev,
310*859bfd8dSPatrick Delaunay 					struct usb_setup_req *req)
311*859bfd8dSPatrick Delaunay {
312*859bfd8dSPatrick Delaunay 	if (pdev->dev_state != USBD_STATE_CONFIGURED) {
313*859bfd8dSPatrick Delaunay 		usb_core_ctl_error(pdev);
314*859bfd8dSPatrick Delaunay 		return USBD_OK;
315*859bfd8dSPatrick Delaunay 	}
316*859bfd8dSPatrick Delaunay 
317*859bfd8dSPatrick Delaunay 	if (LOBYTE(req->index) <= USBD_MAX_NUM_INTERFACES) {
318*859bfd8dSPatrick Delaunay 		pdev->class->setup(pdev, req);
319*859bfd8dSPatrick Delaunay 
320*859bfd8dSPatrick Delaunay 		if (req->length == 0U) {
321*859bfd8dSPatrick Delaunay 			usb_core_transmit_ep0(pdev, NULL, 0U);
322*859bfd8dSPatrick Delaunay 		}
323*859bfd8dSPatrick Delaunay 	} else {
324*859bfd8dSPatrick Delaunay 		usb_core_ctl_error(pdev);
325*859bfd8dSPatrick Delaunay 	}
326*859bfd8dSPatrick Delaunay 
327*859bfd8dSPatrick Delaunay 	return USBD_OK;
328*859bfd8dSPatrick Delaunay }
329*859bfd8dSPatrick Delaunay 
330*859bfd8dSPatrick Delaunay /*
331*859bfd8dSPatrick Delaunay  * usb_core_setup_stage
332*859bfd8dSPatrick Delaunay  *         Handle the setup stage
333*859bfd8dSPatrick Delaunay  * pdev: device instance
334*859bfd8dSPatrick Delaunay  * psetup : setup buffer
335*859bfd8dSPatrick Delaunay  * return : status
336*859bfd8dSPatrick Delaunay  */
337*859bfd8dSPatrick Delaunay static enum usb_status usb_core_setup_stage(struct usb_handle *pdev,
338*859bfd8dSPatrick Delaunay 					    uint8_t *psetup)
339*859bfd8dSPatrick Delaunay {
340*859bfd8dSPatrick Delaunay 	struct usb_setup_req *req = &pdev->request;
341*859bfd8dSPatrick Delaunay 
342*859bfd8dSPatrick Delaunay 	/* Copy setup buffer into req structure */
343*859bfd8dSPatrick Delaunay 	req->bm_request = psetup[0];
344*859bfd8dSPatrick Delaunay 	req->b_request = psetup[1];
345*859bfd8dSPatrick Delaunay 	req->value = psetup[2] + (psetup[3] << 8);
346*859bfd8dSPatrick Delaunay 	req->index = psetup[4] + (psetup[5] << 8);
347*859bfd8dSPatrick Delaunay 	req->length = psetup[6] + (psetup[7] << 8);
348*859bfd8dSPatrick Delaunay 
349*859bfd8dSPatrick Delaunay 	pdev->ep0_state = USBD_EP0_SETUP;
350*859bfd8dSPatrick Delaunay 	pdev->ep0_data_len = pdev->request.length;
351*859bfd8dSPatrick Delaunay 
352*859bfd8dSPatrick Delaunay 	switch (pdev->request.bm_request & USB_REQ_RECIPIENT_MASK) {
353*859bfd8dSPatrick Delaunay 	case USB_REQ_RECIPIENT_DEVICE:
354*859bfd8dSPatrick Delaunay 		usb_core_dev_req(pdev, &pdev->request);
355*859bfd8dSPatrick Delaunay 		break;
356*859bfd8dSPatrick Delaunay 
357*859bfd8dSPatrick Delaunay 	case USB_REQ_RECIPIENT_INTERFACE:
358*859bfd8dSPatrick Delaunay 		usb_core_itf_req(pdev, &pdev->request);
359*859bfd8dSPatrick Delaunay 		break;
360*859bfd8dSPatrick Delaunay 
361*859bfd8dSPatrick Delaunay 	case USB_REQ_RECIPIENT_ENDPOINT:
362*859bfd8dSPatrick Delaunay 	default:
363*859bfd8dSPatrick Delaunay 		ERROR("receive unsupported request %i",
364*859bfd8dSPatrick Delaunay 		      pdev->request.bm_request & USB_REQ_RECIPIENT_MASK);
365*859bfd8dSPatrick Delaunay 		usb_core_set_stall(pdev, pdev->request.bm_request & USB_REQ_DIRECTION);
366*859bfd8dSPatrick Delaunay 		return USBD_FAIL;
367*859bfd8dSPatrick Delaunay 	}
368*859bfd8dSPatrick Delaunay 
369*859bfd8dSPatrick Delaunay 	return USBD_OK;
370*859bfd8dSPatrick Delaunay }
371*859bfd8dSPatrick Delaunay 
372*859bfd8dSPatrick Delaunay /*
373*859bfd8dSPatrick Delaunay  * usb_core_data_out
374*859bfd8dSPatrick Delaunay  *         Handle data OUT stage
375*859bfd8dSPatrick Delaunay  * pdev: device instance
376*859bfd8dSPatrick Delaunay  * epnum: endpoint index
377*859bfd8dSPatrick Delaunay  * pdata: buffer to sent
378*859bfd8dSPatrick Delaunay  * return : status
379*859bfd8dSPatrick Delaunay  */
380*859bfd8dSPatrick Delaunay static enum usb_status usb_core_data_out(struct usb_handle *pdev, uint8_t epnum,
381*859bfd8dSPatrick Delaunay 					 uint8_t *pdata)
382*859bfd8dSPatrick Delaunay {
383*859bfd8dSPatrick Delaunay 	struct usb_endpoint *pep;
384*859bfd8dSPatrick Delaunay 
385*859bfd8dSPatrick Delaunay 	if (epnum == 0U) {
386*859bfd8dSPatrick Delaunay 		pep = &pdev->ep_out[0];
387*859bfd8dSPatrick Delaunay 		if (pdev->ep0_state == USBD_EP0_DATA_OUT) {
388*859bfd8dSPatrick Delaunay 			if (pep->rem_length > pep->maxpacket) {
389*859bfd8dSPatrick Delaunay 				pep->rem_length -= pep->maxpacket;
390*859bfd8dSPatrick Delaunay 
391*859bfd8dSPatrick Delaunay 				usb_core_receive(pdev, 0U, pdata,
392*859bfd8dSPatrick Delaunay 						 MIN(pep->rem_length,
393*859bfd8dSPatrick Delaunay 						     pep->maxpacket));
394*859bfd8dSPatrick Delaunay 			} else {
395*859bfd8dSPatrick Delaunay 				if (pdev->class->ep0_rx_ready &&
396*859bfd8dSPatrick Delaunay 				    (pdev->dev_state == USBD_STATE_CONFIGURED)) {
397*859bfd8dSPatrick Delaunay 					pdev->class->ep0_rx_ready(pdev);
398*859bfd8dSPatrick Delaunay 				}
399*859bfd8dSPatrick Delaunay 
400*859bfd8dSPatrick Delaunay 				usb_core_transmit_ep0(pdev, NULL, 0U);
401*859bfd8dSPatrick Delaunay 			}
402*859bfd8dSPatrick Delaunay 		}
403*859bfd8dSPatrick Delaunay 	} else if (pdev->class->data_out != NULL &&
404*859bfd8dSPatrick Delaunay 		   (pdev->dev_state == USBD_STATE_CONFIGURED)) {
405*859bfd8dSPatrick Delaunay 		pdev->class->data_out(pdev, epnum);
406*859bfd8dSPatrick Delaunay 	}
407*859bfd8dSPatrick Delaunay 
408*859bfd8dSPatrick Delaunay 	return USBD_OK;
409*859bfd8dSPatrick Delaunay }
410*859bfd8dSPatrick Delaunay 
411*859bfd8dSPatrick Delaunay /*
412*859bfd8dSPatrick Delaunay  * usb_core_data_in
413*859bfd8dSPatrick Delaunay  *         Handle data in stage
414*859bfd8dSPatrick Delaunay  * pdev: device instance
415*859bfd8dSPatrick Delaunay  * epnum: endpoint index
416*859bfd8dSPatrick Delaunay  * pdata: buffer to fill
417*859bfd8dSPatrick Delaunay  * return : status
418*859bfd8dSPatrick Delaunay  */
419*859bfd8dSPatrick Delaunay static enum usb_status usb_core_data_in(struct usb_handle *pdev, uint8_t epnum,
420*859bfd8dSPatrick Delaunay 					uint8_t *pdata)
421*859bfd8dSPatrick Delaunay {
422*859bfd8dSPatrick Delaunay 	if (epnum == 0U) {
423*859bfd8dSPatrick Delaunay 		struct usb_endpoint *pep = &pdev->ep_in[0];
424*859bfd8dSPatrick Delaunay 
425*859bfd8dSPatrick Delaunay 		if (pdev->ep0_state == USBD_EP0_DATA_IN) {
426*859bfd8dSPatrick Delaunay 			if (pep->rem_length > pep->maxpacket) {
427*859bfd8dSPatrick Delaunay 				pep->rem_length -= pep->maxpacket;
428*859bfd8dSPatrick Delaunay 
429*859bfd8dSPatrick Delaunay 				usb_core_transmit(pdev, 0U, pdata,
430*859bfd8dSPatrick Delaunay 						  pep->rem_length);
431*859bfd8dSPatrick Delaunay 
432*859bfd8dSPatrick Delaunay 				/* Prepare EP for premature end of transfer */
433*859bfd8dSPatrick Delaunay 				usb_core_receive(pdev, 0U, NULL, 0U);
434*859bfd8dSPatrick Delaunay 			} else {
435*859bfd8dSPatrick Delaunay 				/* Last packet is MPS multiple, send ZLP packet */
436*859bfd8dSPatrick Delaunay 				if ((pep->total_length % pep->maxpacket == 0U) &&
437*859bfd8dSPatrick Delaunay 				    (pep->total_length >= pep->maxpacket) &&
438*859bfd8dSPatrick Delaunay 				    (pep->total_length < pdev->ep0_data_len)) {
439*859bfd8dSPatrick Delaunay 					usb_core_transmit(pdev, 0U, NULL, 0U);
440*859bfd8dSPatrick Delaunay 
441*859bfd8dSPatrick Delaunay 					pdev->ep0_data_len = 0U;
442*859bfd8dSPatrick Delaunay 
443*859bfd8dSPatrick Delaunay 					/* Prepare endpoint for premature end of transfer */
444*859bfd8dSPatrick Delaunay 					usb_core_receive(pdev, 0U, NULL, 0U);
445*859bfd8dSPatrick Delaunay 				} else {
446*859bfd8dSPatrick Delaunay 					if (pdev->class->ep0_tx_sent != NULL &&
447*859bfd8dSPatrick Delaunay 					    (pdev->dev_state ==
448*859bfd8dSPatrick Delaunay 					     USBD_STATE_CONFIGURED)) {
449*859bfd8dSPatrick Delaunay 						pdev->class->ep0_tx_sent(pdev);
450*859bfd8dSPatrick Delaunay 					}
451*859bfd8dSPatrick Delaunay 					/* Start the transfer */
452*859bfd8dSPatrick Delaunay 					usb_core_receive_ep0(pdev, NULL, 0U);
453*859bfd8dSPatrick Delaunay 				}
454*859bfd8dSPatrick Delaunay 			}
455*859bfd8dSPatrick Delaunay 		}
456*859bfd8dSPatrick Delaunay 	} else if ((pdev->class->data_in != NULL) &&
457*859bfd8dSPatrick Delaunay 		  (pdev->dev_state == USBD_STATE_CONFIGURED)) {
458*859bfd8dSPatrick Delaunay 		pdev->class->data_in(pdev, epnum);
459*859bfd8dSPatrick Delaunay 	}
460*859bfd8dSPatrick Delaunay 
461*859bfd8dSPatrick Delaunay 	return USBD_OK;
462*859bfd8dSPatrick Delaunay }
463*859bfd8dSPatrick Delaunay 
464*859bfd8dSPatrick Delaunay /*
465*859bfd8dSPatrick Delaunay  * usb_core_suspend
466*859bfd8dSPatrick Delaunay  *         Handle suspend event
467*859bfd8dSPatrick Delaunay  * pdev : device instance
468*859bfd8dSPatrick Delaunay  * return : status
469*859bfd8dSPatrick Delaunay  */
470*859bfd8dSPatrick Delaunay static enum usb_status usb_core_suspend(struct usb_handle  *pdev)
471*859bfd8dSPatrick Delaunay {
472*859bfd8dSPatrick Delaunay 	INFO("USB Suspend mode\n");
473*859bfd8dSPatrick Delaunay 	pdev->dev_old_state =  pdev->dev_state;
474*859bfd8dSPatrick Delaunay 	pdev->dev_state  = USBD_STATE_SUSPENDED;
475*859bfd8dSPatrick Delaunay 
476*859bfd8dSPatrick Delaunay 	return USBD_OK;
477*859bfd8dSPatrick Delaunay }
478*859bfd8dSPatrick Delaunay 
479*859bfd8dSPatrick Delaunay /*
480*859bfd8dSPatrick Delaunay  * usb_core_resume
481*859bfd8dSPatrick Delaunay  *         Handle resume event
482*859bfd8dSPatrick Delaunay  * pdev : device instance
483*859bfd8dSPatrick Delaunay  * return : status
484*859bfd8dSPatrick Delaunay  */
485*859bfd8dSPatrick Delaunay static enum usb_status usb_core_resume(struct usb_handle *pdev)
486*859bfd8dSPatrick Delaunay {
487*859bfd8dSPatrick Delaunay 	INFO("USB Resume\n");
488*859bfd8dSPatrick Delaunay 	pdev->dev_state = pdev->dev_old_state;
489*859bfd8dSPatrick Delaunay 
490*859bfd8dSPatrick Delaunay 	return USBD_OK;
491*859bfd8dSPatrick Delaunay }
492*859bfd8dSPatrick Delaunay 
493*859bfd8dSPatrick Delaunay /*
494*859bfd8dSPatrick Delaunay  * usb_core_sof
495*859bfd8dSPatrick Delaunay  *         Handle SOF event
496*859bfd8dSPatrick Delaunay  * pdev : device instance
497*859bfd8dSPatrick Delaunay  * return : status
498*859bfd8dSPatrick Delaunay  */
499*859bfd8dSPatrick Delaunay static enum usb_status usb_core_sof(struct usb_handle *pdev)
500*859bfd8dSPatrick Delaunay {
501*859bfd8dSPatrick Delaunay 	if (pdev->dev_state == USBD_STATE_CONFIGURED) {
502*859bfd8dSPatrick Delaunay 		if (pdev->class->sof != NULL) {
503*859bfd8dSPatrick Delaunay 			pdev->class->sof(pdev);
504*859bfd8dSPatrick Delaunay 		}
505*859bfd8dSPatrick Delaunay 	}
506*859bfd8dSPatrick Delaunay 
507*859bfd8dSPatrick Delaunay 	return USBD_OK;
508*859bfd8dSPatrick Delaunay }
509*859bfd8dSPatrick Delaunay 
510*859bfd8dSPatrick Delaunay /*
511*859bfd8dSPatrick Delaunay  * usb_core_disconnect
512*859bfd8dSPatrick Delaunay  *         Handle device disconnection event
513*859bfd8dSPatrick Delaunay  * pdev : device instance
514*859bfd8dSPatrick Delaunay  * return : status
515*859bfd8dSPatrick Delaunay  */
516*859bfd8dSPatrick Delaunay static enum usb_status usb_core_disconnect(struct usb_handle *pdev)
517*859bfd8dSPatrick Delaunay {
518*859bfd8dSPatrick Delaunay 	/* Free class resources */
519*859bfd8dSPatrick Delaunay 	pdev->dev_state = USBD_STATE_DEFAULT;
520*859bfd8dSPatrick Delaunay 	pdev->class->de_init(pdev, pdev->dev_config);
521*859bfd8dSPatrick Delaunay 
522*859bfd8dSPatrick Delaunay 	return USBD_OK;
523*859bfd8dSPatrick Delaunay }
524*859bfd8dSPatrick Delaunay 
525*859bfd8dSPatrick Delaunay enum usb_status usb_core_handle_it(struct usb_handle *pdev)
526*859bfd8dSPatrick Delaunay {
527*859bfd8dSPatrick Delaunay 	uint32_t param = 0U;
528*859bfd8dSPatrick Delaunay 	uint32_t len = 0U;
529*859bfd8dSPatrick Delaunay 	struct usbd_ep *ep;
530*859bfd8dSPatrick Delaunay 
531*859bfd8dSPatrick Delaunay 	switch (pdev->driver->it_handler(pdev->data->instance, &param)) {
532*859bfd8dSPatrick Delaunay 	case USB_DATA_OUT:
533*859bfd8dSPatrick Delaunay 		usb_core_data_out(pdev, param,
534*859bfd8dSPatrick Delaunay 				  pdev->data->out_ep[param].xfer_buff);
535*859bfd8dSPatrick Delaunay 		break;
536*859bfd8dSPatrick Delaunay 
537*859bfd8dSPatrick Delaunay 	case USB_DATA_IN:
538*859bfd8dSPatrick Delaunay 		usb_core_data_in(pdev, param,
539*859bfd8dSPatrick Delaunay 				 pdev->data->in_ep[param].xfer_buff);
540*859bfd8dSPatrick Delaunay 		break;
541*859bfd8dSPatrick Delaunay 
542*859bfd8dSPatrick Delaunay 	case USB_SETUP:
543*859bfd8dSPatrick Delaunay 		usb_core_setup_stage(pdev, (uint8_t *)pdev->data->setup);
544*859bfd8dSPatrick Delaunay 		break;
545*859bfd8dSPatrick Delaunay 
546*859bfd8dSPatrick Delaunay 	case USB_ENUM_DONE:
547*859bfd8dSPatrick Delaunay 		break;
548*859bfd8dSPatrick Delaunay 
549*859bfd8dSPatrick Delaunay 	case USB_READ_DATA_PACKET:
550*859bfd8dSPatrick Delaunay 		ep = &pdev->data->out_ep[param &  USBD_OUT_EPNUM_MASK];
551*859bfd8dSPatrick Delaunay 		len = (param &  USBD_OUT_COUNT_MASK) >> USBD_OUT_COUNT_SHIFT;
552*859bfd8dSPatrick Delaunay 		pdev->driver->read_packet(pdev->data->instance,
553*859bfd8dSPatrick Delaunay 					  ep->xfer_buff, len);
554*859bfd8dSPatrick Delaunay 		ep->xfer_buff += len;
555*859bfd8dSPatrick Delaunay 		ep->xfer_count += len;
556*859bfd8dSPatrick Delaunay 		break;
557*859bfd8dSPatrick Delaunay 
558*859bfd8dSPatrick Delaunay 	case USB_READ_SETUP_PACKET:
559*859bfd8dSPatrick Delaunay 		ep = &pdev->data->out_ep[param &  USBD_OUT_EPNUM_MASK];
560*859bfd8dSPatrick Delaunay 		len = (param &  USBD_OUT_COUNT_MASK) >> 0x10;
561*859bfd8dSPatrick Delaunay 		pdev->driver->read_packet(pdev->data->instance,
562*859bfd8dSPatrick Delaunay 					  (uint8_t *)pdev->data->setup, 8);
563*859bfd8dSPatrick Delaunay 		ep->xfer_count += len;
564*859bfd8dSPatrick Delaunay 		break;
565*859bfd8dSPatrick Delaunay 
566*859bfd8dSPatrick Delaunay 	case USB_RESET:
567*859bfd8dSPatrick Delaunay 		pdev->dev_state = USBD_STATE_DEFAULT;
568*859bfd8dSPatrick Delaunay 		break;
569*859bfd8dSPatrick Delaunay 
570*859bfd8dSPatrick Delaunay 	case USB_RESUME:
571*859bfd8dSPatrick Delaunay 		if (pdev->data->lpm_state == LPM_L1) {
572*859bfd8dSPatrick Delaunay 			pdev->data->lpm_state = LPM_L0;
573*859bfd8dSPatrick Delaunay 		} else {
574*859bfd8dSPatrick Delaunay 			usb_core_resume(pdev);
575*859bfd8dSPatrick Delaunay 		}
576*859bfd8dSPatrick Delaunay 		break;
577*859bfd8dSPatrick Delaunay 
578*859bfd8dSPatrick Delaunay 	case USB_SUSPEND:
579*859bfd8dSPatrick Delaunay 		usb_core_suspend(pdev);
580*859bfd8dSPatrick Delaunay 		break;
581*859bfd8dSPatrick Delaunay 
582*859bfd8dSPatrick Delaunay 	case USB_LPM:
583*859bfd8dSPatrick Delaunay 		if (pdev->data->lpm_state == LPM_L0) {
584*859bfd8dSPatrick Delaunay 			pdev->data->lpm_state = LPM_L1;
585*859bfd8dSPatrick Delaunay 		} else {
586*859bfd8dSPatrick Delaunay 			usb_core_suspend(pdev);
587*859bfd8dSPatrick Delaunay 		}
588*859bfd8dSPatrick Delaunay 		break;
589*859bfd8dSPatrick Delaunay 
590*859bfd8dSPatrick Delaunay 	case USB_SOF:
591*859bfd8dSPatrick Delaunay 		usb_core_sof(pdev);
592*859bfd8dSPatrick Delaunay 		break;
593*859bfd8dSPatrick Delaunay 
594*859bfd8dSPatrick Delaunay 	case USB_DISCONNECT:
595*859bfd8dSPatrick Delaunay 		usb_core_disconnect(pdev);
596*859bfd8dSPatrick Delaunay 		break;
597*859bfd8dSPatrick Delaunay 
598*859bfd8dSPatrick Delaunay 	case USB_WRITE_EMPTY:
599*859bfd8dSPatrick Delaunay 		pdev->driver->write_empty_tx_fifo(pdev->data->instance, param,
600*859bfd8dSPatrick Delaunay 				     pdev->data->in_ep[param].xfer_len,
601*859bfd8dSPatrick Delaunay 				     (uint32_t *)&pdev->data->in_ep[param].xfer_count,
602*859bfd8dSPatrick Delaunay 				     pdev->data->in_ep[param].maxpacket,
603*859bfd8dSPatrick Delaunay 				     &pdev->data->in_ep[param].xfer_buff);
604*859bfd8dSPatrick Delaunay 		break;
605*859bfd8dSPatrick Delaunay 
606*859bfd8dSPatrick Delaunay 	case USB_NOTHING:
607*859bfd8dSPatrick Delaunay 	default:
608*859bfd8dSPatrick Delaunay 		break;
609*859bfd8dSPatrick Delaunay 	}
610*859bfd8dSPatrick Delaunay 
611*859bfd8dSPatrick Delaunay 	return USBD_OK;
612*859bfd8dSPatrick Delaunay }
613*859bfd8dSPatrick Delaunay 
614*859bfd8dSPatrick Delaunay /*
615*859bfd8dSPatrick Delaunay  * usb_core_receive
616*859bfd8dSPatrick Delaunay  *          Receive an amount of data
617*859bfd8dSPatrick Delaunay  * pdev: USB handle
618*859bfd8dSPatrick Delaunay  * ep_addr: endpoint address
619*859bfd8dSPatrick Delaunay  * buf: pointer to the reception buffer
620*859bfd8dSPatrick Delaunay  * len: amount of data to be received
621*859bfd8dSPatrick Delaunay  * return : status
622*859bfd8dSPatrick Delaunay  */
623*859bfd8dSPatrick Delaunay enum usb_status usb_core_receive(struct usb_handle *pdev, uint8_t ep_addr,
624*859bfd8dSPatrick Delaunay 				 uint8_t *buf, uint32_t len)
625*859bfd8dSPatrick Delaunay {
626*859bfd8dSPatrick Delaunay 	struct usbd_ep *ep;
627*859bfd8dSPatrick Delaunay 	struct pcd_handle *hpcd = (struct pcd_handle *)pdev->data;
628*859bfd8dSPatrick Delaunay 	uint8_t num;
629*859bfd8dSPatrick Delaunay 
630*859bfd8dSPatrick Delaunay 	num = ep_addr & EP_NUM_MASK;
631*859bfd8dSPatrick Delaunay 	if (num >= USBD_EP_NB) {
632*859bfd8dSPatrick Delaunay 		return USBD_FAIL;
633*859bfd8dSPatrick Delaunay 	}
634*859bfd8dSPatrick Delaunay 	ep = &hpcd->out_ep[num];
635*859bfd8dSPatrick Delaunay 
636*859bfd8dSPatrick Delaunay 	/* Setup and start the Xfer */
637*859bfd8dSPatrick Delaunay 	ep->xfer_buff = buf;
638*859bfd8dSPatrick Delaunay 	ep->xfer_len = len;
639*859bfd8dSPatrick Delaunay 	ep->xfer_count = 0U;
640*859bfd8dSPatrick Delaunay 	ep->is_in = false;
641*859bfd8dSPatrick Delaunay 	ep->num = num;
642*859bfd8dSPatrick Delaunay 
643*859bfd8dSPatrick Delaunay 	if (num == 0U) {
644*859bfd8dSPatrick Delaunay 		pdev->driver->ep0_start_xfer(hpcd->instance, ep);
645*859bfd8dSPatrick Delaunay 	} else {
646*859bfd8dSPatrick Delaunay 		pdev->driver->ep_start_xfer(hpcd->instance, ep);
647*859bfd8dSPatrick Delaunay 	}
648*859bfd8dSPatrick Delaunay 
649*859bfd8dSPatrick Delaunay 	return USBD_OK;
650*859bfd8dSPatrick Delaunay }
651*859bfd8dSPatrick Delaunay 
652*859bfd8dSPatrick Delaunay /*
653*859bfd8dSPatrick Delaunay  * usb_core_transmit
654*859bfd8dSPatrick Delaunay  *          Send an amount of data
655*859bfd8dSPatrick Delaunay  * pdev: USB handle
656*859bfd8dSPatrick Delaunay  * ep_addr: endpoint address
657*859bfd8dSPatrick Delaunay  * buf: pointer to the transmission buffer
658*859bfd8dSPatrick Delaunay  * len: amount of data to be sent
659*859bfd8dSPatrick Delaunay  * return : status
660*859bfd8dSPatrick Delaunay  */
661*859bfd8dSPatrick Delaunay enum usb_status usb_core_transmit(struct usb_handle *pdev, uint8_t ep_addr,
662*859bfd8dSPatrick Delaunay 				  uint8_t *buf, uint32_t len)
663*859bfd8dSPatrick Delaunay {
664*859bfd8dSPatrick Delaunay 	struct usbd_ep *ep;
665*859bfd8dSPatrick Delaunay 	struct pcd_handle *hpcd = (struct pcd_handle *)pdev->data;
666*859bfd8dSPatrick Delaunay 	uint8_t num;
667*859bfd8dSPatrick Delaunay 
668*859bfd8dSPatrick Delaunay 	num = ep_addr & EP_NUM_MASK;
669*859bfd8dSPatrick Delaunay 	if (num >= USBD_EP_NB) {
670*859bfd8dSPatrick Delaunay 		return USBD_FAIL;
671*859bfd8dSPatrick Delaunay 	}
672*859bfd8dSPatrick Delaunay 	ep = &hpcd->in_ep[num];
673*859bfd8dSPatrick Delaunay 
674*859bfd8dSPatrick Delaunay 	/* Setup and start the Xfer */
675*859bfd8dSPatrick Delaunay 	ep->xfer_buff = buf;
676*859bfd8dSPatrick Delaunay 	ep->xfer_len = len;
677*859bfd8dSPatrick Delaunay 	ep->xfer_count = 0U;
678*859bfd8dSPatrick Delaunay 	ep->is_in = true;
679*859bfd8dSPatrick Delaunay 	ep->num = num;
680*859bfd8dSPatrick Delaunay 
681*859bfd8dSPatrick Delaunay 	if (num == 0U) {
682*859bfd8dSPatrick Delaunay 		pdev->driver->ep0_start_xfer(hpcd->instance, ep);
683*859bfd8dSPatrick Delaunay 	} else {
684*859bfd8dSPatrick Delaunay 		pdev->driver->ep_start_xfer(hpcd->instance, ep);
685*859bfd8dSPatrick Delaunay 	}
686*859bfd8dSPatrick Delaunay 
687*859bfd8dSPatrick Delaunay 	return USBD_OK;
688*859bfd8dSPatrick Delaunay }
689*859bfd8dSPatrick Delaunay 
690*859bfd8dSPatrick Delaunay /*
691*859bfd8dSPatrick Delaunay  * usb_core_receive_ep0
692*859bfd8dSPatrick Delaunay  *          Receive an amount of data on ep0
693*859bfd8dSPatrick Delaunay  * pdev: USB handle
694*859bfd8dSPatrick Delaunay  * buf: pointer to the reception buffer
695*859bfd8dSPatrick Delaunay  * len: amount of data to be received
696*859bfd8dSPatrick Delaunay  * return : status
697*859bfd8dSPatrick Delaunay  */
698*859bfd8dSPatrick Delaunay enum usb_status usb_core_receive_ep0(struct usb_handle *pdev, uint8_t *buf,
699*859bfd8dSPatrick Delaunay 				     uint32_t len)
700*859bfd8dSPatrick Delaunay {
701*859bfd8dSPatrick Delaunay 	/* Prepare the reception of the buffer over EP0 */
702*859bfd8dSPatrick Delaunay 	if (len != 0U) {
703*859bfd8dSPatrick Delaunay 		pdev->ep0_state = USBD_EP0_DATA_OUT;
704*859bfd8dSPatrick Delaunay 	} else {
705*859bfd8dSPatrick Delaunay 		pdev->ep0_state = USBD_EP0_STATUS_OUT;
706*859bfd8dSPatrick Delaunay 	}
707*859bfd8dSPatrick Delaunay 
708*859bfd8dSPatrick Delaunay 	pdev->ep_out[0].total_length = len;
709*859bfd8dSPatrick Delaunay 	pdev->ep_out[0].rem_length = len;
710*859bfd8dSPatrick Delaunay 
711*859bfd8dSPatrick Delaunay 	/* Start the transfer */
712*859bfd8dSPatrick Delaunay 	return usb_core_receive(pdev, 0U, buf, len);
713*859bfd8dSPatrick Delaunay }
714*859bfd8dSPatrick Delaunay 
715*859bfd8dSPatrick Delaunay /*
716*859bfd8dSPatrick Delaunay  * usb_core_transmit_ep0
717*859bfd8dSPatrick Delaunay  *          Send an amount of data on ep0
718*859bfd8dSPatrick Delaunay  * pdev: USB handle
719*859bfd8dSPatrick Delaunay  * buf: pointer to the transmission buffer
720*859bfd8dSPatrick Delaunay  * len: amount of data to be sent
721*859bfd8dSPatrick Delaunay  * return : status
722*859bfd8dSPatrick Delaunay  */
723*859bfd8dSPatrick Delaunay enum usb_status usb_core_transmit_ep0(struct usb_handle *pdev, uint8_t *buf,
724*859bfd8dSPatrick Delaunay 				      uint32_t len)
725*859bfd8dSPatrick Delaunay {
726*859bfd8dSPatrick Delaunay 	/* Set EP0 State */
727*859bfd8dSPatrick Delaunay 	if (len != 0U) {
728*859bfd8dSPatrick Delaunay 		pdev->ep0_state = USBD_EP0_DATA_IN;
729*859bfd8dSPatrick Delaunay 	} else {
730*859bfd8dSPatrick Delaunay 		pdev->ep0_state = USBD_EP0_STATUS_IN;
731*859bfd8dSPatrick Delaunay 	}
732*859bfd8dSPatrick Delaunay 
733*859bfd8dSPatrick Delaunay 	pdev->ep_in[0].total_length = len;
734*859bfd8dSPatrick Delaunay 	pdev->ep_in[0].rem_length = len;
735*859bfd8dSPatrick Delaunay 
736*859bfd8dSPatrick Delaunay 	/* Start the transfer */
737*859bfd8dSPatrick Delaunay 	return usb_core_transmit(pdev, 0U, buf, len);
738*859bfd8dSPatrick Delaunay }
739*859bfd8dSPatrick Delaunay 
740*859bfd8dSPatrick Delaunay /*
741*859bfd8dSPatrick Delaunay  * usb_core_ctl_error
742*859bfd8dSPatrick Delaunay  *         Handle USB low level error
743*859bfd8dSPatrick Delaunay  * pdev: device instance
744*859bfd8dSPatrick Delaunay  * req: usb request
745*859bfd8dSPatrick Delaunay  * return : None
746*859bfd8dSPatrick Delaunay  */
747*859bfd8dSPatrick Delaunay 
748*859bfd8dSPatrick Delaunay void usb_core_ctl_error(struct usb_handle *pdev)
749*859bfd8dSPatrick Delaunay {
750*859bfd8dSPatrick Delaunay 	ERROR("%s : Send an ERROR\n", __func__);
751*859bfd8dSPatrick Delaunay 	usb_core_set_stall(pdev, EP0_IN);
752*859bfd8dSPatrick Delaunay 	usb_core_set_stall(pdev, EP0_OUT);
753*859bfd8dSPatrick Delaunay }
754*859bfd8dSPatrick Delaunay 
755*859bfd8dSPatrick Delaunay /*
756*859bfd8dSPatrick Delaunay  * usb_core_start
757*859bfd8dSPatrick Delaunay  *         Start the USB device core.
758*859bfd8dSPatrick Delaunay  * pdev: Device Handle
759*859bfd8dSPatrick Delaunay  * return : USBD Status
760*859bfd8dSPatrick Delaunay  */
761*859bfd8dSPatrick Delaunay enum usb_status usb_core_start(struct usb_handle *pdev)
762*859bfd8dSPatrick Delaunay {
763*859bfd8dSPatrick Delaunay 	/* Start the low level driver */
764*859bfd8dSPatrick Delaunay 	pdev->driver->start_device(pdev->data->instance);
765*859bfd8dSPatrick Delaunay 
766*859bfd8dSPatrick Delaunay 	return USBD_OK;
767*859bfd8dSPatrick Delaunay }
768*859bfd8dSPatrick Delaunay 
769*859bfd8dSPatrick Delaunay /*
770*859bfd8dSPatrick Delaunay  * usb_core_stop
771*859bfd8dSPatrick Delaunay  *         Stop the USB device core.
772*859bfd8dSPatrick Delaunay  * pdev: Device Handle
773*859bfd8dSPatrick Delaunay  * return : USBD Status
774*859bfd8dSPatrick Delaunay  */
775*859bfd8dSPatrick Delaunay enum usb_status usb_core_stop(struct usb_handle *pdev)
776*859bfd8dSPatrick Delaunay {
777*859bfd8dSPatrick Delaunay 	/* Free class resources */
778*859bfd8dSPatrick Delaunay 	pdev->class->de_init(pdev, pdev->dev_config);
779*859bfd8dSPatrick Delaunay 
780*859bfd8dSPatrick Delaunay 	/* Stop the low level driver */
781*859bfd8dSPatrick Delaunay 	pdev->driver->stop_device(pdev->data->instance);
782*859bfd8dSPatrick Delaunay 
783*859bfd8dSPatrick Delaunay 	return USBD_OK;
784*859bfd8dSPatrick Delaunay }
785*859bfd8dSPatrick Delaunay 
786*859bfd8dSPatrick Delaunay /*
787*859bfd8dSPatrick Delaunay  * register_usb_driver
788*859bfd8dSPatrick Delaunay  *         Stop the USB device core.
789*859bfd8dSPatrick Delaunay  * pdev: Device Handle
790*859bfd8dSPatrick Delaunay  * pcd_handle: PCD handle
791*859bfd8dSPatrick Delaunay  * driver: USB driver
792*859bfd8dSPatrick Delaunay  * driver_handle: USB driver handle
793*859bfd8dSPatrick Delaunay  * return : USBD Status
794*859bfd8dSPatrick Delaunay  */
795*859bfd8dSPatrick Delaunay enum usb_status register_usb_driver(struct usb_handle *pdev,
796*859bfd8dSPatrick Delaunay 				    struct pcd_handle *pcd_handle,
797*859bfd8dSPatrick Delaunay 				    const struct usb_driver *driver,
798*859bfd8dSPatrick Delaunay 				    void *driver_handle)
799*859bfd8dSPatrick Delaunay {
800*859bfd8dSPatrick Delaunay 	uint8_t i;
801*859bfd8dSPatrick Delaunay 
802*859bfd8dSPatrick Delaunay 	assert(pdev != NULL);
803*859bfd8dSPatrick Delaunay 	assert(pcd_handle != NULL);
804*859bfd8dSPatrick Delaunay 	assert(driver != NULL);
805*859bfd8dSPatrick Delaunay 	assert(driver_handle != NULL);
806*859bfd8dSPatrick Delaunay 
807*859bfd8dSPatrick Delaunay 	/* Free class resources */
808*859bfd8dSPatrick Delaunay 	pdev->driver = driver;
809*859bfd8dSPatrick Delaunay 	pdev->data = pcd_handle;
810*859bfd8dSPatrick Delaunay 	pdev->data->instance = driver_handle;
811*859bfd8dSPatrick Delaunay 	pdev->dev_state = USBD_STATE_DEFAULT;
812*859bfd8dSPatrick Delaunay 	pdev->ep0_state = USBD_EP0_IDLE;
813*859bfd8dSPatrick Delaunay 
814*859bfd8dSPatrick Delaunay 	/* Copy endpoint information */
815*859bfd8dSPatrick Delaunay 	for (i = 0U; i < USBD_EP_NB; i++) {
816*859bfd8dSPatrick Delaunay 		pdev->ep_in[i].maxpacket = pdev->data->in_ep[i].maxpacket;
817*859bfd8dSPatrick Delaunay 		pdev->ep_out[i].maxpacket = pdev->data->out_ep[i].maxpacket;
818*859bfd8dSPatrick Delaunay 	}
819*859bfd8dSPatrick Delaunay 
820*859bfd8dSPatrick Delaunay 	return USBD_OK;
821*859bfd8dSPatrick Delaunay }
822*859bfd8dSPatrick Delaunay 
823*859bfd8dSPatrick Delaunay /*
824*859bfd8dSPatrick Delaunay  * register_platform
825*859bfd8dSPatrick Delaunay  *         Register the USB device core.
826*859bfd8dSPatrick Delaunay  * pdev: Device Handle
827*859bfd8dSPatrick Delaunay  * plat_call_back: callback
828*859bfd8dSPatrick Delaunay  * return : USBD Status
829*859bfd8dSPatrick Delaunay  */
830*859bfd8dSPatrick Delaunay enum usb_status register_platform(struct usb_handle *pdev,
831*859bfd8dSPatrick Delaunay 			       const struct usb_desc *plat_call_back)
832*859bfd8dSPatrick Delaunay {
833*859bfd8dSPatrick Delaunay 	assert(pdev != NULL);
834*859bfd8dSPatrick Delaunay 	assert(plat_call_back != NULL);
835*859bfd8dSPatrick Delaunay 
836*859bfd8dSPatrick Delaunay 	/* Save platform info in class resources */
837*859bfd8dSPatrick Delaunay 	pdev->desc = plat_call_back;
838*859bfd8dSPatrick Delaunay 
839*859bfd8dSPatrick Delaunay 	return USBD_OK;
840*859bfd8dSPatrick Delaunay }
841