xref: /rk3399_ARM-atf/drivers/usb/usb_device.c (revision 216c1223c2c65bd1c119a28b9406f70a9ee7b063)
1859bfd8dSPatrick Delaunay /*
2859bfd8dSPatrick Delaunay  * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
3859bfd8dSPatrick Delaunay  *
4859bfd8dSPatrick Delaunay  * SPDX-License-Identifier: BSD-3-Clause
5859bfd8dSPatrick Delaunay  */
6859bfd8dSPatrick Delaunay 
7859bfd8dSPatrick Delaunay #include <assert.h>
8859bfd8dSPatrick Delaunay #include <stdint.h>
9859bfd8dSPatrick Delaunay 
10859bfd8dSPatrick Delaunay #include <common/debug.h>
11859bfd8dSPatrick Delaunay #include <drivers/usb_device.h>
12859bfd8dSPatrick Delaunay 
13859bfd8dSPatrick Delaunay /* Define for EP address */
14859bfd8dSPatrick Delaunay #define EP_DIR_MASK		BIT(7)
15859bfd8dSPatrick Delaunay #define EP_DIR_IN		BIT(7)
16859bfd8dSPatrick Delaunay #define EP_NUM_MASK		GENMASK(3, 0)
17859bfd8dSPatrick Delaunay 
18859bfd8dSPatrick Delaunay #define EP0_IN			(0U | EP_DIR_IN)
19859bfd8dSPatrick Delaunay #define EP0_OUT			0U
20859bfd8dSPatrick Delaunay 
21859bfd8dSPatrick Delaunay /* USB address between 1 through 127 = 0x7F mask */
22859bfd8dSPatrick Delaunay #define ADDRESS_MASK		GENMASK(6, 0)
23859bfd8dSPatrick Delaunay 
24859bfd8dSPatrick Delaunay /*
25859bfd8dSPatrick Delaunay  * Set a STALL condition over an endpoint
26859bfd8dSPatrick Delaunay  * pdev: USB handle
27859bfd8dSPatrick Delaunay  * ep_addr: endpoint address
28859bfd8dSPatrick Delaunay  * return : status
29859bfd8dSPatrick Delaunay  */
30859bfd8dSPatrick Delaunay static enum usb_status usb_core_set_stall(struct usb_handle *pdev, uint8_t ep_addr)
31859bfd8dSPatrick Delaunay {
32859bfd8dSPatrick Delaunay 	struct usbd_ep *ep;
33859bfd8dSPatrick Delaunay 	struct pcd_handle *hpcd = (struct pcd_handle *)pdev->data;
34859bfd8dSPatrick Delaunay 	uint8_t num;
35859bfd8dSPatrick Delaunay 
36859bfd8dSPatrick Delaunay 	num = ep_addr & EP_NUM_MASK;
37859bfd8dSPatrick Delaunay 	if (num >= USBD_EP_NB) {
38859bfd8dSPatrick Delaunay 		return USBD_FAIL;
39859bfd8dSPatrick Delaunay 	}
40859bfd8dSPatrick Delaunay 	if ((EP_DIR_MASK & ep_addr) == EP_DIR_IN) {
41859bfd8dSPatrick Delaunay 		ep = &hpcd->in_ep[num];
42859bfd8dSPatrick Delaunay 		ep->is_in = true;
43859bfd8dSPatrick Delaunay 	} else {
44859bfd8dSPatrick Delaunay 		ep = &hpcd->out_ep[num];
45859bfd8dSPatrick Delaunay 		ep->is_in = false;
46859bfd8dSPatrick Delaunay 	}
47859bfd8dSPatrick Delaunay 	ep->num = num;
48859bfd8dSPatrick Delaunay 
49859bfd8dSPatrick Delaunay 	pdev->driver->ep_set_stall(hpcd->instance, ep);
50859bfd8dSPatrick Delaunay 	if (num == 0U) {
51859bfd8dSPatrick Delaunay 		pdev->driver->ep0_out_start(hpcd->instance);
52859bfd8dSPatrick Delaunay 	}
53859bfd8dSPatrick Delaunay 
54859bfd8dSPatrick Delaunay 	return USBD_OK;
55859bfd8dSPatrick Delaunay }
56859bfd8dSPatrick Delaunay 
57859bfd8dSPatrick Delaunay /*
58859bfd8dSPatrick Delaunay  * usb_core_get_desc
59859bfd8dSPatrick Delaunay  *         Handle Get Descriptor requests
60859bfd8dSPatrick Delaunay  * pdev : device instance
61859bfd8dSPatrick Delaunay  * req : usb request
62859bfd8dSPatrick Delaunay  */
63859bfd8dSPatrick Delaunay static void usb_core_get_desc(struct usb_handle *pdev, struct usb_setup_req *req)
64859bfd8dSPatrick Delaunay {
65859bfd8dSPatrick Delaunay 	uint16_t len;
66859bfd8dSPatrick Delaunay 	uint8_t *pbuf;
67859bfd8dSPatrick Delaunay 	uint8_t desc_type = HIBYTE(req->value);
68859bfd8dSPatrick Delaunay 	uint8_t desc_idx = LOBYTE(req->value);
69859bfd8dSPatrick Delaunay 
70859bfd8dSPatrick Delaunay 	switch (desc_type) {
71859bfd8dSPatrick Delaunay 	case USB_DESC_TYPE_DEVICE:
72859bfd8dSPatrick Delaunay 		pbuf = pdev->desc->get_device_desc(&len);
73859bfd8dSPatrick Delaunay 		break;
74859bfd8dSPatrick Delaunay 
75859bfd8dSPatrick Delaunay 	case USB_DESC_TYPE_CONFIGURATION:
76025f5ef2SPatrick Delaunay 		pbuf = pdev->desc->get_config_desc(&len);
77859bfd8dSPatrick Delaunay 		break;
78859bfd8dSPatrick Delaunay 
79859bfd8dSPatrick Delaunay 	case USB_DESC_TYPE_STRING:
80859bfd8dSPatrick Delaunay 		switch (desc_idx) {
81859bfd8dSPatrick Delaunay 		case USBD_IDX_LANGID_STR:
82859bfd8dSPatrick Delaunay 			pbuf = pdev->desc->get_lang_id_desc(&len);
83859bfd8dSPatrick Delaunay 			break;
84859bfd8dSPatrick Delaunay 
85859bfd8dSPatrick Delaunay 		case USBD_IDX_MFC_STR:
86859bfd8dSPatrick Delaunay 			pbuf = pdev->desc->get_manufacturer_desc(&len);
87859bfd8dSPatrick Delaunay 			break;
88859bfd8dSPatrick Delaunay 
89859bfd8dSPatrick Delaunay 		case USBD_IDX_PRODUCT_STR:
90859bfd8dSPatrick Delaunay 			pbuf = pdev->desc->get_product_desc(&len);
91859bfd8dSPatrick Delaunay 			break;
92859bfd8dSPatrick Delaunay 
93859bfd8dSPatrick Delaunay 		case USBD_IDX_SERIAL_STR:
94859bfd8dSPatrick Delaunay 			pbuf = pdev->desc->get_serial_desc(&len);
95859bfd8dSPatrick Delaunay 			break;
96859bfd8dSPatrick Delaunay 
97859bfd8dSPatrick Delaunay 		case USBD_IDX_CONFIG_STR:
98859bfd8dSPatrick Delaunay 			pbuf = pdev->desc->get_configuration_desc(&len);
99859bfd8dSPatrick Delaunay 			break;
100859bfd8dSPatrick Delaunay 
101859bfd8dSPatrick Delaunay 		case USBD_IDX_INTERFACE_STR:
102859bfd8dSPatrick Delaunay 			pbuf = pdev->desc->get_interface_desc(&len);
103859bfd8dSPatrick Delaunay 			break;
104859bfd8dSPatrick Delaunay 
105859bfd8dSPatrick Delaunay 		/* For all USER string */
106859bfd8dSPatrick Delaunay 		case USBD_IDX_USER0_STR:
107859bfd8dSPatrick Delaunay 		default:
108859bfd8dSPatrick Delaunay 			pbuf = pdev->desc->get_usr_desc(desc_idx - USBD_IDX_USER0_STR, &len);
109859bfd8dSPatrick Delaunay 			break;
110859bfd8dSPatrick Delaunay 		}
111859bfd8dSPatrick Delaunay 		break;
112859bfd8dSPatrick Delaunay 
113859bfd8dSPatrick Delaunay 	case USB_DESC_TYPE_DEVICE_QUALIFIER:
114025f5ef2SPatrick Delaunay 		pbuf = pdev->desc->get_device_qualifier_desc(&len);
115859bfd8dSPatrick Delaunay 		break;
116859bfd8dSPatrick Delaunay 
117859bfd8dSPatrick Delaunay 	case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION:
118*216c1223SPatrick Delaunay 		if (pdev->desc->get_other_speed_config_desc == NULL) {
119*216c1223SPatrick Delaunay 			usb_core_ctl_error(pdev);
120*216c1223SPatrick Delaunay 			return;
121*216c1223SPatrick Delaunay 		}
122*216c1223SPatrick Delaunay 		pbuf = pdev->desc->get_other_speed_config_desc(&len);
123859bfd8dSPatrick Delaunay 		break;
124859bfd8dSPatrick Delaunay 
125859bfd8dSPatrick Delaunay 	default:
126859bfd8dSPatrick Delaunay 		ERROR("Unknown request %i\n", desc_type);
127859bfd8dSPatrick Delaunay 		usb_core_ctl_error(pdev);
128859bfd8dSPatrick Delaunay 		return;
129859bfd8dSPatrick Delaunay 	}
130859bfd8dSPatrick Delaunay 
131859bfd8dSPatrick Delaunay 	if ((len != 0U) && (req->length != 0U)) {
132859bfd8dSPatrick Delaunay 		len = MIN(len, req->length);
133859bfd8dSPatrick Delaunay 
134859bfd8dSPatrick Delaunay 		/* Start the transfer */
135859bfd8dSPatrick Delaunay 		usb_core_transmit_ep0(pdev, pbuf, len);
136859bfd8dSPatrick Delaunay 	}
137859bfd8dSPatrick Delaunay }
138859bfd8dSPatrick Delaunay 
139859bfd8dSPatrick Delaunay /*
140859bfd8dSPatrick Delaunay  * usb_core_set_config
141859bfd8dSPatrick Delaunay  *         Handle Set device configuration request
142859bfd8dSPatrick Delaunay  * pdev : device instance
143859bfd8dSPatrick Delaunay  * req : usb request
144859bfd8dSPatrick Delaunay  */
145859bfd8dSPatrick Delaunay static void usb_core_set_config(struct usb_handle *pdev, struct usb_setup_req *req)
146859bfd8dSPatrick Delaunay {
147859bfd8dSPatrick Delaunay 	static uint8_t cfgidx;
148859bfd8dSPatrick Delaunay 
149859bfd8dSPatrick Delaunay 	cfgidx = LOBYTE(req->value);
150859bfd8dSPatrick Delaunay 
151859bfd8dSPatrick Delaunay 	if (cfgidx > USBD_MAX_NUM_CONFIGURATION) {
152859bfd8dSPatrick Delaunay 		usb_core_ctl_error(pdev);
153859bfd8dSPatrick Delaunay 		return;
154859bfd8dSPatrick Delaunay 	}
155859bfd8dSPatrick Delaunay 
156859bfd8dSPatrick Delaunay 	switch (pdev->dev_state) {
157859bfd8dSPatrick Delaunay 	case USBD_STATE_ADDRESSED:
158859bfd8dSPatrick Delaunay 		if (cfgidx != 0U) {
159859bfd8dSPatrick Delaunay 			pdev->dev_config = cfgidx;
160859bfd8dSPatrick Delaunay 			pdev->dev_state = USBD_STATE_CONFIGURED;
161859bfd8dSPatrick Delaunay 			if (!pdev->class) {
162859bfd8dSPatrick Delaunay 				usb_core_ctl_error(pdev);
163859bfd8dSPatrick Delaunay 				return;
164859bfd8dSPatrick Delaunay 			}
165859bfd8dSPatrick Delaunay 			/* Set configuration and Start the Class */
166859bfd8dSPatrick Delaunay 			if (pdev->class->init(pdev, cfgidx) != 0U) {
167859bfd8dSPatrick Delaunay 				usb_core_ctl_error(pdev);
168859bfd8dSPatrick Delaunay 				return;
169859bfd8dSPatrick Delaunay 			}
170859bfd8dSPatrick Delaunay 		}
171859bfd8dSPatrick Delaunay 		break;
172859bfd8dSPatrick Delaunay 
173859bfd8dSPatrick Delaunay 	case USBD_STATE_CONFIGURED:
174859bfd8dSPatrick Delaunay 		if (cfgidx == 0U) {
175859bfd8dSPatrick Delaunay 			pdev->dev_state = USBD_STATE_ADDRESSED;
176859bfd8dSPatrick Delaunay 			pdev->dev_config = cfgidx;
177859bfd8dSPatrick Delaunay 			pdev->class->de_init(pdev, cfgidx);
178859bfd8dSPatrick Delaunay 		} else if (cfgidx != pdev->dev_config) {
179859bfd8dSPatrick Delaunay 			if (pdev->class != NULL) {
180859bfd8dSPatrick Delaunay 				usb_core_ctl_error(pdev);
181859bfd8dSPatrick Delaunay 				return;
182859bfd8dSPatrick Delaunay 			}
183859bfd8dSPatrick Delaunay 			/* Clear old configuration */
184859bfd8dSPatrick Delaunay 			pdev->class->de_init(pdev, pdev->dev_config);
185859bfd8dSPatrick Delaunay 			/* Set new configuration */
186859bfd8dSPatrick Delaunay 			pdev->dev_config = cfgidx;
187859bfd8dSPatrick Delaunay 			/* Set configuration and start the USB class */
188859bfd8dSPatrick Delaunay 			if (pdev->class->init(pdev, cfgidx) != 0U) {
189859bfd8dSPatrick Delaunay 				usb_core_ctl_error(pdev);
190859bfd8dSPatrick Delaunay 				return;
191859bfd8dSPatrick Delaunay 			}
192859bfd8dSPatrick Delaunay 		}
193859bfd8dSPatrick Delaunay 		break;
194859bfd8dSPatrick Delaunay 
195859bfd8dSPatrick Delaunay 	default:
196859bfd8dSPatrick Delaunay 		usb_core_ctl_error(pdev);
197859bfd8dSPatrick Delaunay 		return;
198859bfd8dSPatrick Delaunay 	}
199859bfd8dSPatrick Delaunay 
200859bfd8dSPatrick Delaunay 	/* Send status */
201859bfd8dSPatrick Delaunay 	usb_core_transmit_ep0(pdev, NULL, 0U);
202859bfd8dSPatrick Delaunay }
203859bfd8dSPatrick Delaunay 
204859bfd8dSPatrick Delaunay /*
205859bfd8dSPatrick Delaunay  * usb_core_get_status
206859bfd8dSPatrick Delaunay  *         Handle Get Status request
207859bfd8dSPatrick Delaunay  * pdev : device instance
208859bfd8dSPatrick Delaunay  * req : usb request
209859bfd8dSPatrick Delaunay  */
210859bfd8dSPatrick Delaunay static void usb_core_get_status(struct usb_handle *pdev,
211859bfd8dSPatrick Delaunay 				struct usb_setup_req *req)
212859bfd8dSPatrick Delaunay {
213859bfd8dSPatrick Delaunay 	if ((pdev->dev_state != USBD_STATE_ADDRESSED) &&
214859bfd8dSPatrick Delaunay 	    (pdev->dev_state != USBD_STATE_CONFIGURED)) {
215859bfd8dSPatrick Delaunay 		usb_core_ctl_error(pdev);
216859bfd8dSPatrick Delaunay 		return;
217859bfd8dSPatrick Delaunay 	}
218859bfd8dSPatrick Delaunay 
219859bfd8dSPatrick Delaunay 	pdev->dev_config_status = USB_CONFIG_SELF_POWERED;
220859bfd8dSPatrick Delaunay 
221859bfd8dSPatrick Delaunay 	if (pdev->dev_remote_wakeup != 0U) {
222859bfd8dSPatrick Delaunay 		pdev->dev_config_status |= USB_CONFIG_REMOTE_WAKEUP;
223859bfd8dSPatrick Delaunay 	}
224859bfd8dSPatrick Delaunay 
225859bfd8dSPatrick Delaunay 	/* Start the transfer */
226859bfd8dSPatrick Delaunay 	usb_core_transmit_ep0(pdev, (uint8_t *)&pdev->dev_config_status, 2U);
227859bfd8dSPatrick Delaunay }
228859bfd8dSPatrick Delaunay 
229859bfd8dSPatrick Delaunay /*
230859bfd8dSPatrick Delaunay  * usb_core_set_address
231859bfd8dSPatrick Delaunay  *         Set device address
232859bfd8dSPatrick Delaunay  * pdev : device instance
233859bfd8dSPatrick Delaunay  * req : usb request
234859bfd8dSPatrick Delaunay  */
235859bfd8dSPatrick Delaunay static void usb_core_set_address(struct usb_handle *pdev,
236859bfd8dSPatrick Delaunay 				 struct usb_setup_req *req)
237859bfd8dSPatrick Delaunay {
238859bfd8dSPatrick Delaunay 	uint8_t dev_addr;
239859bfd8dSPatrick Delaunay 
240859bfd8dSPatrick Delaunay 	if ((req->index != 0U) || (req->length != 0U)) {
241859bfd8dSPatrick Delaunay 		usb_core_ctl_error(pdev);
242859bfd8dSPatrick Delaunay 		return;
243859bfd8dSPatrick Delaunay 	}
244859bfd8dSPatrick Delaunay 
245859bfd8dSPatrick Delaunay 	dev_addr = req->value & ADDRESS_MASK;
246859bfd8dSPatrick Delaunay 	if (pdev->dev_state != USBD_STATE_DEFAULT) {
247859bfd8dSPatrick Delaunay 		usb_core_ctl_error(pdev);
248859bfd8dSPatrick Delaunay 		return;
249859bfd8dSPatrick Delaunay 	}
250859bfd8dSPatrick Delaunay 
251859bfd8dSPatrick Delaunay 	pdev->dev_address = dev_addr;
252859bfd8dSPatrick Delaunay 	pdev->driver->set_address(((struct pcd_handle *)(pdev->data))->instance, dev_addr);
253859bfd8dSPatrick Delaunay 
254859bfd8dSPatrick Delaunay 	/* Send status */
255859bfd8dSPatrick Delaunay 	usb_core_transmit_ep0(pdev, NULL, 0U);
256859bfd8dSPatrick Delaunay 
257859bfd8dSPatrick Delaunay 	if (dev_addr != 0U) {
258859bfd8dSPatrick Delaunay 		pdev->dev_state  = USBD_STATE_ADDRESSED;
259859bfd8dSPatrick Delaunay 	} else {
260859bfd8dSPatrick Delaunay 		pdev->dev_state  = USBD_STATE_DEFAULT;
261859bfd8dSPatrick Delaunay 	}
262859bfd8dSPatrick Delaunay }
263859bfd8dSPatrick Delaunay 
264859bfd8dSPatrick Delaunay /*
265859bfd8dSPatrick Delaunay  * usb_core_dev_req
266859bfd8dSPatrick Delaunay  *         Handle standard usb device requests
267859bfd8dSPatrick Delaunay  * pdev : device instance
268859bfd8dSPatrick Delaunay  * req : usb request
269859bfd8dSPatrick Delaunay  * return : status
270859bfd8dSPatrick Delaunay  */
271859bfd8dSPatrick Delaunay static enum usb_status usb_core_dev_req(struct usb_handle *pdev,
272859bfd8dSPatrick Delaunay 					struct usb_setup_req *req)
273859bfd8dSPatrick Delaunay {
274859bfd8dSPatrick Delaunay 	VERBOSE("receive request %i\n", req->b_request);
275859bfd8dSPatrick Delaunay 	switch (req->b_request) {
276859bfd8dSPatrick Delaunay 	case USB_REQ_GET_DESCRIPTOR:
277859bfd8dSPatrick Delaunay 		usb_core_get_desc(pdev, req);
278859bfd8dSPatrick Delaunay 		break;
279859bfd8dSPatrick Delaunay 
280859bfd8dSPatrick Delaunay 	case USB_REQ_SET_CONFIGURATION:
281859bfd8dSPatrick Delaunay 		usb_core_set_config(pdev, req);
282859bfd8dSPatrick Delaunay 		break;
283859bfd8dSPatrick Delaunay 
284859bfd8dSPatrick Delaunay 	case USB_REQ_GET_STATUS:
285859bfd8dSPatrick Delaunay 		usb_core_get_status(pdev, req);
286859bfd8dSPatrick Delaunay 		break;
287859bfd8dSPatrick Delaunay 
288859bfd8dSPatrick Delaunay 	case USB_REQ_SET_ADDRESS:
289859bfd8dSPatrick Delaunay 		usb_core_set_address(pdev, req);
290859bfd8dSPatrick Delaunay 		break;
291859bfd8dSPatrick Delaunay 
292859bfd8dSPatrick Delaunay 	case USB_REQ_GET_CONFIGURATION:
293859bfd8dSPatrick Delaunay 	case USB_REQ_SET_FEATURE:
294859bfd8dSPatrick Delaunay 	case USB_REQ_CLEAR_FEATURE:
295859bfd8dSPatrick Delaunay 	default:
296859bfd8dSPatrick Delaunay 		ERROR("NOT SUPPORTED %i\n", req->b_request);
297859bfd8dSPatrick Delaunay 		usb_core_ctl_error(pdev);
298859bfd8dSPatrick Delaunay 		break;
299859bfd8dSPatrick Delaunay 	}
300859bfd8dSPatrick Delaunay 
301859bfd8dSPatrick Delaunay 	return USBD_OK;
302859bfd8dSPatrick Delaunay }
303859bfd8dSPatrick Delaunay 
304859bfd8dSPatrick Delaunay /*
305859bfd8dSPatrick Delaunay  * usb_core_itf_req
306859bfd8dSPatrick Delaunay  *         Handle standard usb interface requests
307859bfd8dSPatrick Delaunay  * pdev : device instance
308859bfd8dSPatrick Delaunay  * req : usb request
309859bfd8dSPatrick Delaunay  * return : status
310859bfd8dSPatrick Delaunay  */
311859bfd8dSPatrick Delaunay static enum usb_status usb_core_itf_req(struct usb_handle *pdev,
312859bfd8dSPatrick Delaunay 					struct usb_setup_req *req)
313859bfd8dSPatrick Delaunay {
314859bfd8dSPatrick Delaunay 	if (pdev->dev_state != USBD_STATE_CONFIGURED) {
315859bfd8dSPatrick Delaunay 		usb_core_ctl_error(pdev);
316859bfd8dSPatrick Delaunay 		return USBD_OK;
317859bfd8dSPatrick Delaunay 	}
318859bfd8dSPatrick Delaunay 
319859bfd8dSPatrick Delaunay 	if (LOBYTE(req->index) <= USBD_MAX_NUM_INTERFACES) {
320859bfd8dSPatrick Delaunay 		pdev->class->setup(pdev, req);
321859bfd8dSPatrick Delaunay 
322859bfd8dSPatrick Delaunay 		if (req->length == 0U) {
323859bfd8dSPatrick Delaunay 			usb_core_transmit_ep0(pdev, NULL, 0U);
324859bfd8dSPatrick Delaunay 		}
325859bfd8dSPatrick Delaunay 	} else {
326859bfd8dSPatrick Delaunay 		usb_core_ctl_error(pdev);
327859bfd8dSPatrick Delaunay 	}
328859bfd8dSPatrick Delaunay 
329859bfd8dSPatrick Delaunay 	return USBD_OK;
330859bfd8dSPatrick Delaunay }
331859bfd8dSPatrick Delaunay 
332859bfd8dSPatrick Delaunay /*
333859bfd8dSPatrick Delaunay  * usb_core_setup_stage
334859bfd8dSPatrick Delaunay  *         Handle the setup stage
335859bfd8dSPatrick Delaunay  * pdev: device instance
336859bfd8dSPatrick Delaunay  * psetup : setup buffer
337859bfd8dSPatrick Delaunay  * return : status
338859bfd8dSPatrick Delaunay  */
339859bfd8dSPatrick Delaunay static enum usb_status usb_core_setup_stage(struct usb_handle *pdev,
340859bfd8dSPatrick Delaunay 					    uint8_t *psetup)
341859bfd8dSPatrick Delaunay {
342859bfd8dSPatrick Delaunay 	struct usb_setup_req *req = &pdev->request;
343859bfd8dSPatrick Delaunay 
344859bfd8dSPatrick Delaunay 	/* Copy setup buffer into req structure */
345859bfd8dSPatrick Delaunay 	req->bm_request = psetup[0];
346859bfd8dSPatrick Delaunay 	req->b_request = psetup[1];
347859bfd8dSPatrick Delaunay 	req->value = psetup[2] + (psetup[3] << 8);
348859bfd8dSPatrick Delaunay 	req->index = psetup[4] + (psetup[5] << 8);
349859bfd8dSPatrick Delaunay 	req->length = psetup[6] + (psetup[7] << 8);
350859bfd8dSPatrick Delaunay 
351859bfd8dSPatrick Delaunay 	pdev->ep0_state = USBD_EP0_SETUP;
352859bfd8dSPatrick Delaunay 	pdev->ep0_data_len = pdev->request.length;
353859bfd8dSPatrick Delaunay 
354859bfd8dSPatrick Delaunay 	switch (pdev->request.bm_request & USB_REQ_RECIPIENT_MASK) {
355859bfd8dSPatrick Delaunay 	case USB_REQ_RECIPIENT_DEVICE:
356859bfd8dSPatrick Delaunay 		usb_core_dev_req(pdev, &pdev->request);
357859bfd8dSPatrick Delaunay 		break;
358859bfd8dSPatrick Delaunay 
359859bfd8dSPatrick Delaunay 	case USB_REQ_RECIPIENT_INTERFACE:
360859bfd8dSPatrick Delaunay 		usb_core_itf_req(pdev, &pdev->request);
361859bfd8dSPatrick Delaunay 		break;
362859bfd8dSPatrick Delaunay 
363859bfd8dSPatrick Delaunay 	case USB_REQ_RECIPIENT_ENDPOINT:
364859bfd8dSPatrick Delaunay 	default:
365859bfd8dSPatrick Delaunay 		ERROR("receive unsupported request %i",
366859bfd8dSPatrick Delaunay 		      pdev->request.bm_request & USB_REQ_RECIPIENT_MASK);
367859bfd8dSPatrick Delaunay 		usb_core_set_stall(pdev, pdev->request.bm_request & USB_REQ_DIRECTION);
368859bfd8dSPatrick Delaunay 		return USBD_FAIL;
369859bfd8dSPatrick Delaunay 	}
370859bfd8dSPatrick Delaunay 
371859bfd8dSPatrick Delaunay 	return USBD_OK;
372859bfd8dSPatrick Delaunay }
373859bfd8dSPatrick Delaunay 
374859bfd8dSPatrick Delaunay /*
375859bfd8dSPatrick Delaunay  * usb_core_data_out
376859bfd8dSPatrick Delaunay  *         Handle data OUT stage
377859bfd8dSPatrick Delaunay  * pdev: device instance
378859bfd8dSPatrick Delaunay  * epnum: endpoint index
379859bfd8dSPatrick Delaunay  * pdata: buffer to sent
380859bfd8dSPatrick Delaunay  * return : status
381859bfd8dSPatrick Delaunay  */
382859bfd8dSPatrick Delaunay static enum usb_status usb_core_data_out(struct usb_handle *pdev, uint8_t epnum,
383859bfd8dSPatrick Delaunay 					 uint8_t *pdata)
384859bfd8dSPatrick Delaunay {
385859bfd8dSPatrick Delaunay 	struct usb_endpoint *pep;
386859bfd8dSPatrick Delaunay 
387859bfd8dSPatrick Delaunay 	if (epnum == 0U) {
388859bfd8dSPatrick Delaunay 		pep = &pdev->ep_out[0];
389859bfd8dSPatrick Delaunay 		if (pdev->ep0_state == USBD_EP0_DATA_OUT) {
390859bfd8dSPatrick Delaunay 			if (pep->rem_length > pep->maxpacket) {
391859bfd8dSPatrick Delaunay 				pep->rem_length -= pep->maxpacket;
392859bfd8dSPatrick Delaunay 
393859bfd8dSPatrick Delaunay 				usb_core_receive(pdev, 0U, pdata,
394859bfd8dSPatrick Delaunay 						 MIN(pep->rem_length,
395859bfd8dSPatrick Delaunay 						     pep->maxpacket));
396859bfd8dSPatrick Delaunay 			} else {
397859bfd8dSPatrick Delaunay 				if (pdev->class->ep0_rx_ready &&
398859bfd8dSPatrick Delaunay 				    (pdev->dev_state == USBD_STATE_CONFIGURED)) {
399859bfd8dSPatrick Delaunay 					pdev->class->ep0_rx_ready(pdev);
400859bfd8dSPatrick Delaunay 				}
401859bfd8dSPatrick Delaunay 
402859bfd8dSPatrick Delaunay 				usb_core_transmit_ep0(pdev, NULL, 0U);
403859bfd8dSPatrick Delaunay 			}
404859bfd8dSPatrick Delaunay 		}
405859bfd8dSPatrick Delaunay 	} else if (pdev->class->data_out != NULL &&
406859bfd8dSPatrick Delaunay 		   (pdev->dev_state == USBD_STATE_CONFIGURED)) {
407859bfd8dSPatrick Delaunay 		pdev->class->data_out(pdev, epnum);
408859bfd8dSPatrick Delaunay 	}
409859bfd8dSPatrick Delaunay 
410859bfd8dSPatrick Delaunay 	return USBD_OK;
411859bfd8dSPatrick Delaunay }
412859bfd8dSPatrick Delaunay 
413859bfd8dSPatrick Delaunay /*
414859bfd8dSPatrick Delaunay  * usb_core_data_in
415859bfd8dSPatrick Delaunay  *         Handle data in stage
416859bfd8dSPatrick Delaunay  * pdev: device instance
417859bfd8dSPatrick Delaunay  * epnum: endpoint index
418859bfd8dSPatrick Delaunay  * pdata: buffer to fill
419859bfd8dSPatrick Delaunay  * return : status
420859bfd8dSPatrick Delaunay  */
421859bfd8dSPatrick Delaunay static enum usb_status usb_core_data_in(struct usb_handle *pdev, uint8_t epnum,
422859bfd8dSPatrick Delaunay 					uint8_t *pdata)
423859bfd8dSPatrick Delaunay {
424859bfd8dSPatrick Delaunay 	if (epnum == 0U) {
425859bfd8dSPatrick Delaunay 		struct usb_endpoint *pep = &pdev->ep_in[0];
426859bfd8dSPatrick Delaunay 
427859bfd8dSPatrick Delaunay 		if (pdev->ep0_state == USBD_EP0_DATA_IN) {
428859bfd8dSPatrick Delaunay 			if (pep->rem_length > pep->maxpacket) {
429859bfd8dSPatrick Delaunay 				pep->rem_length -= pep->maxpacket;
430859bfd8dSPatrick Delaunay 
431859bfd8dSPatrick Delaunay 				usb_core_transmit(pdev, 0U, pdata,
432859bfd8dSPatrick Delaunay 						  pep->rem_length);
433859bfd8dSPatrick Delaunay 
434859bfd8dSPatrick Delaunay 				/* Prepare EP for premature end of transfer */
435859bfd8dSPatrick Delaunay 				usb_core_receive(pdev, 0U, NULL, 0U);
436859bfd8dSPatrick Delaunay 			} else {
437859bfd8dSPatrick Delaunay 				/* Last packet is MPS multiple, send ZLP packet */
438859bfd8dSPatrick Delaunay 				if ((pep->total_length % pep->maxpacket == 0U) &&
439859bfd8dSPatrick Delaunay 				    (pep->total_length >= pep->maxpacket) &&
440859bfd8dSPatrick Delaunay 				    (pep->total_length < pdev->ep0_data_len)) {
441859bfd8dSPatrick Delaunay 					usb_core_transmit(pdev, 0U, NULL, 0U);
442859bfd8dSPatrick Delaunay 
443859bfd8dSPatrick Delaunay 					pdev->ep0_data_len = 0U;
444859bfd8dSPatrick Delaunay 
445859bfd8dSPatrick Delaunay 					/* Prepare endpoint for premature end of transfer */
446859bfd8dSPatrick Delaunay 					usb_core_receive(pdev, 0U, NULL, 0U);
447859bfd8dSPatrick Delaunay 				} else {
448859bfd8dSPatrick Delaunay 					if (pdev->class->ep0_tx_sent != NULL &&
449859bfd8dSPatrick Delaunay 					    (pdev->dev_state ==
450859bfd8dSPatrick Delaunay 					     USBD_STATE_CONFIGURED)) {
451859bfd8dSPatrick Delaunay 						pdev->class->ep0_tx_sent(pdev);
452859bfd8dSPatrick Delaunay 					}
453859bfd8dSPatrick Delaunay 					/* Start the transfer */
454859bfd8dSPatrick Delaunay 					usb_core_receive_ep0(pdev, NULL, 0U);
455859bfd8dSPatrick Delaunay 				}
456859bfd8dSPatrick Delaunay 			}
457859bfd8dSPatrick Delaunay 		}
458859bfd8dSPatrick Delaunay 	} else if ((pdev->class->data_in != NULL) &&
459859bfd8dSPatrick Delaunay 		  (pdev->dev_state == USBD_STATE_CONFIGURED)) {
460859bfd8dSPatrick Delaunay 		pdev->class->data_in(pdev, epnum);
461859bfd8dSPatrick Delaunay 	}
462859bfd8dSPatrick Delaunay 
463859bfd8dSPatrick Delaunay 	return USBD_OK;
464859bfd8dSPatrick Delaunay }
465859bfd8dSPatrick Delaunay 
466859bfd8dSPatrick Delaunay /*
467859bfd8dSPatrick Delaunay  * usb_core_suspend
468859bfd8dSPatrick Delaunay  *         Handle suspend event
469859bfd8dSPatrick Delaunay  * pdev : device instance
470859bfd8dSPatrick Delaunay  * return : status
471859bfd8dSPatrick Delaunay  */
472859bfd8dSPatrick Delaunay static enum usb_status usb_core_suspend(struct usb_handle  *pdev)
473859bfd8dSPatrick Delaunay {
474859bfd8dSPatrick Delaunay 	INFO("USB Suspend mode\n");
475859bfd8dSPatrick Delaunay 	pdev->dev_old_state =  pdev->dev_state;
476859bfd8dSPatrick Delaunay 	pdev->dev_state  = USBD_STATE_SUSPENDED;
477859bfd8dSPatrick Delaunay 
478859bfd8dSPatrick Delaunay 	return USBD_OK;
479859bfd8dSPatrick Delaunay }
480859bfd8dSPatrick Delaunay 
481859bfd8dSPatrick Delaunay /*
482859bfd8dSPatrick Delaunay  * usb_core_resume
483859bfd8dSPatrick Delaunay  *         Handle resume event
484859bfd8dSPatrick Delaunay  * pdev : device instance
485859bfd8dSPatrick Delaunay  * return : status
486859bfd8dSPatrick Delaunay  */
487859bfd8dSPatrick Delaunay static enum usb_status usb_core_resume(struct usb_handle *pdev)
488859bfd8dSPatrick Delaunay {
489859bfd8dSPatrick Delaunay 	INFO("USB Resume\n");
490859bfd8dSPatrick Delaunay 	pdev->dev_state = pdev->dev_old_state;
491859bfd8dSPatrick Delaunay 
492859bfd8dSPatrick Delaunay 	return USBD_OK;
493859bfd8dSPatrick Delaunay }
494859bfd8dSPatrick Delaunay 
495859bfd8dSPatrick Delaunay /*
496859bfd8dSPatrick Delaunay  * usb_core_sof
497859bfd8dSPatrick Delaunay  *         Handle SOF event
498859bfd8dSPatrick Delaunay  * pdev : device instance
499859bfd8dSPatrick Delaunay  * return : status
500859bfd8dSPatrick Delaunay  */
501859bfd8dSPatrick Delaunay static enum usb_status usb_core_sof(struct usb_handle *pdev)
502859bfd8dSPatrick Delaunay {
503859bfd8dSPatrick Delaunay 	if (pdev->dev_state == USBD_STATE_CONFIGURED) {
504859bfd8dSPatrick Delaunay 		if (pdev->class->sof != NULL) {
505859bfd8dSPatrick Delaunay 			pdev->class->sof(pdev);
506859bfd8dSPatrick Delaunay 		}
507859bfd8dSPatrick Delaunay 	}
508859bfd8dSPatrick Delaunay 
509859bfd8dSPatrick Delaunay 	return USBD_OK;
510859bfd8dSPatrick Delaunay }
511859bfd8dSPatrick Delaunay 
512859bfd8dSPatrick Delaunay /*
513859bfd8dSPatrick Delaunay  * usb_core_disconnect
514859bfd8dSPatrick Delaunay  *         Handle device disconnection event
515859bfd8dSPatrick Delaunay  * pdev : device instance
516859bfd8dSPatrick Delaunay  * return : status
517859bfd8dSPatrick Delaunay  */
518859bfd8dSPatrick Delaunay static enum usb_status usb_core_disconnect(struct usb_handle *pdev)
519859bfd8dSPatrick Delaunay {
520859bfd8dSPatrick Delaunay 	/* Free class resources */
521859bfd8dSPatrick Delaunay 	pdev->dev_state = USBD_STATE_DEFAULT;
522859bfd8dSPatrick Delaunay 	pdev->class->de_init(pdev, pdev->dev_config);
523859bfd8dSPatrick Delaunay 
524859bfd8dSPatrick Delaunay 	return USBD_OK;
525859bfd8dSPatrick Delaunay }
526859bfd8dSPatrick Delaunay 
527859bfd8dSPatrick Delaunay enum usb_status usb_core_handle_it(struct usb_handle *pdev)
528859bfd8dSPatrick Delaunay {
529859bfd8dSPatrick Delaunay 	uint32_t param = 0U;
530859bfd8dSPatrick Delaunay 	uint32_t len = 0U;
531859bfd8dSPatrick Delaunay 	struct usbd_ep *ep;
532859bfd8dSPatrick Delaunay 
533859bfd8dSPatrick Delaunay 	switch (pdev->driver->it_handler(pdev->data->instance, &param)) {
534859bfd8dSPatrick Delaunay 	case USB_DATA_OUT:
535859bfd8dSPatrick Delaunay 		usb_core_data_out(pdev, param,
536859bfd8dSPatrick Delaunay 				  pdev->data->out_ep[param].xfer_buff);
537859bfd8dSPatrick Delaunay 		break;
538859bfd8dSPatrick Delaunay 
539859bfd8dSPatrick Delaunay 	case USB_DATA_IN:
540859bfd8dSPatrick Delaunay 		usb_core_data_in(pdev, param,
541859bfd8dSPatrick Delaunay 				 pdev->data->in_ep[param].xfer_buff);
542859bfd8dSPatrick Delaunay 		break;
543859bfd8dSPatrick Delaunay 
544859bfd8dSPatrick Delaunay 	case USB_SETUP:
545859bfd8dSPatrick Delaunay 		usb_core_setup_stage(pdev, (uint8_t *)pdev->data->setup);
546859bfd8dSPatrick Delaunay 		break;
547859bfd8dSPatrick Delaunay 
548859bfd8dSPatrick Delaunay 	case USB_ENUM_DONE:
549859bfd8dSPatrick Delaunay 		break;
550859bfd8dSPatrick Delaunay 
551859bfd8dSPatrick Delaunay 	case USB_READ_DATA_PACKET:
552859bfd8dSPatrick Delaunay 		ep = &pdev->data->out_ep[param &  USBD_OUT_EPNUM_MASK];
553859bfd8dSPatrick Delaunay 		len = (param &  USBD_OUT_COUNT_MASK) >> USBD_OUT_COUNT_SHIFT;
554859bfd8dSPatrick Delaunay 		pdev->driver->read_packet(pdev->data->instance,
555859bfd8dSPatrick Delaunay 					  ep->xfer_buff, len);
556859bfd8dSPatrick Delaunay 		ep->xfer_buff += len;
557859bfd8dSPatrick Delaunay 		ep->xfer_count += len;
558859bfd8dSPatrick Delaunay 		break;
559859bfd8dSPatrick Delaunay 
560859bfd8dSPatrick Delaunay 	case USB_READ_SETUP_PACKET:
561859bfd8dSPatrick Delaunay 		ep = &pdev->data->out_ep[param &  USBD_OUT_EPNUM_MASK];
562859bfd8dSPatrick Delaunay 		len = (param &  USBD_OUT_COUNT_MASK) >> 0x10;
563859bfd8dSPatrick Delaunay 		pdev->driver->read_packet(pdev->data->instance,
564859bfd8dSPatrick Delaunay 					  (uint8_t *)pdev->data->setup, 8);
565859bfd8dSPatrick Delaunay 		ep->xfer_count += len;
566859bfd8dSPatrick Delaunay 		break;
567859bfd8dSPatrick Delaunay 
568859bfd8dSPatrick Delaunay 	case USB_RESET:
569859bfd8dSPatrick Delaunay 		pdev->dev_state = USBD_STATE_DEFAULT;
570859bfd8dSPatrick Delaunay 		break;
571859bfd8dSPatrick Delaunay 
572859bfd8dSPatrick Delaunay 	case USB_RESUME:
573859bfd8dSPatrick Delaunay 		if (pdev->data->lpm_state == LPM_L1) {
574859bfd8dSPatrick Delaunay 			pdev->data->lpm_state = LPM_L0;
575859bfd8dSPatrick Delaunay 		} else {
576859bfd8dSPatrick Delaunay 			usb_core_resume(pdev);
577859bfd8dSPatrick Delaunay 		}
578859bfd8dSPatrick Delaunay 		break;
579859bfd8dSPatrick Delaunay 
580859bfd8dSPatrick Delaunay 	case USB_SUSPEND:
581859bfd8dSPatrick Delaunay 		usb_core_suspend(pdev);
582859bfd8dSPatrick Delaunay 		break;
583859bfd8dSPatrick Delaunay 
584859bfd8dSPatrick Delaunay 	case USB_LPM:
585859bfd8dSPatrick Delaunay 		if (pdev->data->lpm_state == LPM_L0) {
586859bfd8dSPatrick Delaunay 			pdev->data->lpm_state = LPM_L1;
587859bfd8dSPatrick Delaunay 		} else {
588859bfd8dSPatrick Delaunay 			usb_core_suspend(pdev);
589859bfd8dSPatrick Delaunay 		}
590859bfd8dSPatrick Delaunay 		break;
591859bfd8dSPatrick Delaunay 
592859bfd8dSPatrick Delaunay 	case USB_SOF:
593859bfd8dSPatrick Delaunay 		usb_core_sof(pdev);
594859bfd8dSPatrick Delaunay 		break;
595859bfd8dSPatrick Delaunay 
596859bfd8dSPatrick Delaunay 	case USB_DISCONNECT:
597859bfd8dSPatrick Delaunay 		usb_core_disconnect(pdev);
598859bfd8dSPatrick Delaunay 		break;
599859bfd8dSPatrick Delaunay 
600859bfd8dSPatrick Delaunay 	case USB_WRITE_EMPTY:
601859bfd8dSPatrick Delaunay 		pdev->driver->write_empty_tx_fifo(pdev->data->instance, param,
602859bfd8dSPatrick Delaunay 				     pdev->data->in_ep[param].xfer_len,
603859bfd8dSPatrick Delaunay 				     (uint32_t *)&pdev->data->in_ep[param].xfer_count,
604859bfd8dSPatrick Delaunay 				     pdev->data->in_ep[param].maxpacket,
605859bfd8dSPatrick Delaunay 				     &pdev->data->in_ep[param].xfer_buff);
606859bfd8dSPatrick Delaunay 		break;
607859bfd8dSPatrick Delaunay 
608859bfd8dSPatrick Delaunay 	case USB_NOTHING:
609859bfd8dSPatrick Delaunay 	default:
610859bfd8dSPatrick Delaunay 		break;
611859bfd8dSPatrick Delaunay 	}
612859bfd8dSPatrick Delaunay 
613859bfd8dSPatrick Delaunay 	return USBD_OK;
614859bfd8dSPatrick Delaunay }
615859bfd8dSPatrick Delaunay 
616859bfd8dSPatrick Delaunay /*
617859bfd8dSPatrick Delaunay  * usb_core_receive
618859bfd8dSPatrick Delaunay  *          Receive an amount of data
619859bfd8dSPatrick Delaunay  * pdev: USB handle
620859bfd8dSPatrick Delaunay  * ep_addr: endpoint address
621859bfd8dSPatrick Delaunay  * buf: pointer to the reception buffer
622859bfd8dSPatrick Delaunay  * len: amount of data to be received
623859bfd8dSPatrick Delaunay  * return : status
624859bfd8dSPatrick Delaunay  */
625859bfd8dSPatrick Delaunay enum usb_status usb_core_receive(struct usb_handle *pdev, uint8_t ep_addr,
626859bfd8dSPatrick Delaunay 				 uint8_t *buf, uint32_t len)
627859bfd8dSPatrick Delaunay {
628859bfd8dSPatrick Delaunay 	struct usbd_ep *ep;
629859bfd8dSPatrick Delaunay 	struct pcd_handle *hpcd = (struct pcd_handle *)pdev->data;
630859bfd8dSPatrick Delaunay 	uint8_t num;
631859bfd8dSPatrick Delaunay 
632859bfd8dSPatrick Delaunay 	num = ep_addr & EP_NUM_MASK;
633859bfd8dSPatrick Delaunay 	if (num >= USBD_EP_NB) {
634859bfd8dSPatrick Delaunay 		return USBD_FAIL;
635859bfd8dSPatrick Delaunay 	}
636859bfd8dSPatrick Delaunay 	ep = &hpcd->out_ep[num];
637859bfd8dSPatrick Delaunay 
638859bfd8dSPatrick Delaunay 	/* Setup and start the Xfer */
639859bfd8dSPatrick Delaunay 	ep->xfer_buff = buf;
640859bfd8dSPatrick Delaunay 	ep->xfer_len = len;
641859bfd8dSPatrick Delaunay 	ep->xfer_count = 0U;
642859bfd8dSPatrick Delaunay 	ep->is_in = false;
643859bfd8dSPatrick Delaunay 	ep->num = num;
644859bfd8dSPatrick Delaunay 
645859bfd8dSPatrick Delaunay 	if (num == 0U) {
646859bfd8dSPatrick Delaunay 		pdev->driver->ep0_start_xfer(hpcd->instance, ep);
647859bfd8dSPatrick Delaunay 	} else {
648859bfd8dSPatrick Delaunay 		pdev->driver->ep_start_xfer(hpcd->instance, ep);
649859bfd8dSPatrick Delaunay 	}
650859bfd8dSPatrick Delaunay 
651859bfd8dSPatrick Delaunay 	return USBD_OK;
652859bfd8dSPatrick Delaunay }
653859bfd8dSPatrick Delaunay 
654859bfd8dSPatrick Delaunay /*
655859bfd8dSPatrick Delaunay  * usb_core_transmit
656859bfd8dSPatrick Delaunay  *          Send an amount of data
657859bfd8dSPatrick Delaunay  * pdev: USB handle
658859bfd8dSPatrick Delaunay  * ep_addr: endpoint address
659859bfd8dSPatrick Delaunay  * buf: pointer to the transmission buffer
660859bfd8dSPatrick Delaunay  * len: amount of data to be sent
661859bfd8dSPatrick Delaunay  * return : status
662859bfd8dSPatrick Delaunay  */
663859bfd8dSPatrick Delaunay enum usb_status usb_core_transmit(struct usb_handle *pdev, uint8_t ep_addr,
664859bfd8dSPatrick Delaunay 				  uint8_t *buf, uint32_t len)
665859bfd8dSPatrick Delaunay {
666859bfd8dSPatrick Delaunay 	struct usbd_ep *ep;
667859bfd8dSPatrick Delaunay 	struct pcd_handle *hpcd = (struct pcd_handle *)pdev->data;
668859bfd8dSPatrick Delaunay 	uint8_t num;
669859bfd8dSPatrick Delaunay 
670859bfd8dSPatrick Delaunay 	num = ep_addr & EP_NUM_MASK;
671859bfd8dSPatrick Delaunay 	if (num >= USBD_EP_NB) {
672859bfd8dSPatrick Delaunay 		return USBD_FAIL;
673859bfd8dSPatrick Delaunay 	}
674859bfd8dSPatrick Delaunay 	ep = &hpcd->in_ep[num];
675859bfd8dSPatrick Delaunay 
676859bfd8dSPatrick Delaunay 	/* Setup and start the Xfer */
677859bfd8dSPatrick Delaunay 	ep->xfer_buff = buf;
678859bfd8dSPatrick Delaunay 	ep->xfer_len = len;
679859bfd8dSPatrick Delaunay 	ep->xfer_count = 0U;
680859bfd8dSPatrick Delaunay 	ep->is_in = true;
681859bfd8dSPatrick Delaunay 	ep->num = num;
682859bfd8dSPatrick Delaunay 
683859bfd8dSPatrick Delaunay 	if (num == 0U) {
684859bfd8dSPatrick Delaunay 		pdev->driver->ep0_start_xfer(hpcd->instance, ep);
685859bfd8dSPatrick Delaunay 	} else {
686859bfd8dSPatrick Delaunay 		pdev->driver->ep_start_xfer(hpcd->instance, ep);
687859bfd8dSPatrick Delaunay 	}
688859bfd8dSPatrick Delaunay 
689859bfd8dSPatrick Delaunay 	return USBD_OK;
690859bfd8dSPatrick Delaunay }
691859bfd8dSPatrick Delaunay 
692859bfd8dSPatrick Delaunay /*
693859bfd8dSPatrick Delaunay  * usb_core_receive_ep0
694859bfd8dSPatrick Delaunay  *          Receive an amount of data on ep0
695859bfd8dSPatrick Delaunay  * pdev: USB handle
696859bfd8dSPatrick Delaunay  * buf: pointer to the reception buffer
697859bfd8dSPatrick Delaunay  * len: amount of data to be received
698859bfd8dSPatrick Delaunay  * return : status
699859bfd8dSPatrick Delaunay  */
700859bfd8dSPatrick Delaunay enum usb_status usb_core_receive_ep0(struct usb_handle *pdev, uint8_t *buf,
701859bfd8dSPatrick Delaunay 				     uint32_t len)
702859bfd8dSPatrick Delaunay {
703859bfd8dSPatrick Delaunay 	/* Prepare the reception of the buffer over EP0 */
704859bfd8dSPatrick Delaunay 	if (len != 0U) {
705859bfd8dSPatrick Delaunay 		pdev->ep0_state = USBD_EP0_DATA_OUT;
706859bfd8dSPatrick Delaunay 	} else {
707859bfd8dSPatrick Delaunay 		pdev->ep0_state = USBD_EP0_STATUS_OUT;
708859bfd8dSPatrick Delaunay 	}
709859bfd8dSPatrick Delaunay 
710859bfd8dSPatrick Delaunay 	pdev->ep_out[0].total_length = len;
711859bfd8dSPatrick Delaunay 	pdev->ep_out[0].rem_length = len;
712859bfd8dSPatrick Delaunay 
713859bfd8dSPatrick Delaunay 	/* Start the transfer */
714859bfd8dSPatrick Delaunay 	return usb_core_receive(pdev, 0U, buf, len);
715859bfd8dSPatrick Delaunay }
716859bfd8dSPatrick Delaunay 
717859bfd8dSPatrick Delaunay /*
718859bfd8dSPatrick Delaunay  * usb_core_transmit_ep0
719859bfd8dSPatrick Delaunay  *          Send an amount of data on ep0
720859bfd8dSPatrick Delaunay  * pdev: USB handle
721859bfd8dSPatrick Delaunay  * buf: pointer to the transmission buffer
722859bfd8dSPatrick Delaunay  * len: amount of data to be sent
723859bfd8dSPatrick Delaunay  * return : status
724859bfd8dSPatrick Delaunay  */
725859bfd8dSPatrick Delaunay enum usb_status usb_core_transmit_ep0(struct usb_handle *pdev, uint8_t *buf,
726859bfd8dSPatrick Delaunay 				      uint32_t len)
727859bfd8dSPatrick Delaunay {
728859bfd8dSPatrick Delaunay 	/* Set EP0 State */
729859bfd8dSPatrick Delaunay 	if (len != 0U) {
730859bfd8dSPatrick Delaunay 		pdev->ep0_state = USBD_EP0_DATA_IN;
731859bfd8dSPatrick Delaunay 	} else {
732859bfd8dSPatrick Delaunay 		pdev->ep0_state = USBD_EP0_STATUS_IN;
733859bfd8dSPatrick Delaunay 	}
734859bfd8dSPatrick Delaunay 
735859bfd8dSPatrick Delaunay 	pdev->ep_in[0].total_length = len;
736859bfd8dSPatrick Delaunay 	pdev->ep_in[0].rem_length = len;
737859bfd8dSPatrick Delaunay 
738859bfd8dSPatrick Delaunay 	/* Start the transfer */
739859bfd8dSPatrick Delaunay 	return usb_core_transmit(pdev, 0U, buf, len);
740859bfd8dSPatrick Delaunay }
741859bfd8dSPatrick Delaunay 
742859bfd8dSPatrick Delaunay /*
743859bfd8dSPatrick Delaunay  * usb_core_ctl_error
744859bfd8dSPatrick Delaunay  *         Handle USB low level error
745859bfd8dSPatrick Delaunay  * pdev: device instance
746859bfd8dSPatrick Delaunay  * req: usb request
747859bfd8dSPatrick Delaunay  * return : None
748859bfd8dSPatrick Delaunay  */
749859bfd8dSPatrick Delaunay 
750859bfd8dSPatrick Delaunay void usb_core_ctl_error(struct usb_handle *pdev)
751859bfd8dSPatrick Delaunay {
752859bfd8dSPatrick Delaunay 	ERROR("%s : Send an ERROR\n", __func__);
753859bfd8dSPatrick Delaunay 	usb_core_set_stall(pdev, EP0_IN);
754859bfd8dSPatrick Delaunay 	usb_core_set_stall(pdev, EP0_OUT);
755859bfd8dSPatrick Delaunay }
756859bfd8dSPatrick Delaunay 
757859bfd8dSPatrick Delaunay /*
758859bfd8dSPatrick Delaunay  * usb_core_start
759859bfd8dSPatrick Delaunay  *         Start the USB device core.
760859bfd8dSPatrick Delaunay  * pdev: Device Handle
761859bfd8dSPatrick Delaunay  * return : USBD Status
762859bfd8dSPatrick Delaunay  */
763859bfd8dSPatrick Delaunay enum usb_status usb_core_start(struct usb_handle *pdev)
764859bfd8dSPatrick Delaunay {
765859bfd8dSPatrick Delaunay 	/* Start the low level driver */
766859bfd8dSPatrick Delaunay 	pdev->driver->start_device(pdev->data->instance);
767859bfd8dSPatrick Delaunay 
768859bfd8dSPatrick Delaunay 	return USBD_OK;
769859bfd8dSPatrick Delaunay }
770859bfd8dSPatrick Delaunay 
771859bfd8dSPatrick Delaunay /*
772859bfd8dSPatrick Delaunay  * usb_core_stop
773859bfd8dSPatrick Delaunay  *         Stop the USB device core.
774859bfd8dSPatrick Delaunay  * pdev: Device Handle
775859bfd8dSPatrick Delaunay  * return : USBD Status
776859bfd8dSPatrick Delaunay  */
777859bfd8dSPatrick Delaunay enum usb_status usb_core_stop(struct usb_handle *pdev)
778859bfd8dSPatrick Delaunay {
779859bfd8dSPatrick Delaunay 	/* Free class resources */
780859bfd8dSPatrick Delaunay 	pdev->class->de_init(pdev, pdev->dev_config);
781859bfd8dSPatrick Delaunay 
782859bfd8dSPatrick Delaunay 	/* Stop the low level driver */
783859bfd8dSPatrick Delaunay 	pdev->driver->stop_device(pdev->data->instance);
784859bfd8dSPatrick Delaunay 
785859bfd8dSPatrick Delaunay 	return USBD_OK;
786859bfd8dSPatrick Delaunay }
787859bfd8dSPatrick Delaunay 
788859bfd8dSPatrick Delaunay /*
789859bfd8dSPatrick Delaunay  * register_usb_driver
790859bfd8dSPatrick Delaunay  *         Stop the USB device core.
791859bfd8dSPatrick Delaunay  * pdev: Device Handle
792859bfd8dSPatrick Delaunay  * pcd_handle: PCD handle
793859bfd8dSPatrick Delaunay  * driver: USB driver
794859bfd8dSPatrick Delaunay  * driver_handle: USB driver handle
795859bfd8dSPatrick Delaunay  * return : USBD Status
796859bfd8dSPatrick Delaunay  */
797859bfd8dSPatrick Delaunay enum usb_status register_usb_driver(struct usb_handle *pdev,
798859bfd8dSPatrick Delaunay 				    struct pcd_handle *pcd_handle,
799859bfd8dSPatrick Delaunay 				    const struct usb_driver *driver,
800859bfd8dSPatrick Delaunay 				    void *driver_handle)
801859bfd8dSPatrick Delaunay {
802859bfd8dSPatrick Delaunay 	uint8_t i;
803859bfd8dSPatrick Delaunay 
804859bfd8dSPatrick Delaunay 	assert(pdev != NULL);
805859bfd8dSPatrick Delaunay 	assert(pcd_handle != NULL);
806859bfd8dSPatrick Delaunay 	assert(driver != NULL);
807859bfd8dSPatrick Delaunay 	assert(driver_handle != NULL);
808859bfd8dSPatrick Delaunay 
809859bfd8dSPatrick Delaunay 	/* Free class resources */
810859bfd8dSPatrick Delaunay 	pdev->driver = driver;
811859bfd8dSPatrick Delaunay 	pdev->data = pcd_handle;
812859bfd8dSPatrick Delaunay 	pdev->data->instance = driver_handle;
813859bfd8dSPatrick Delaunay 	pdev->dev_state = USBD_STATE_DEFAULT;
814859bfd8dSPatrick Delaunay 	pdev->ep0_state = USBD_EP0_IDLE;
815859bfd8dSPatrick Delaunay 
816859bfd8dSPatrick Delaunay 	/* Copy endpoint information */
817859bfd8dSPatrick Delaunay 	for (i = 0U; i < USBD_EP_NB; i++) {
818859bfd8dSPatrick Delaunay 		pdev->ep_in[i].maxpacket = pdev->data->in_ep[i].maxpacket;
819859bfd8dSPatrick Delaunay 		pdev->ep_out[i].maxpacket = pdev->data->out_ep[i].maxpacket;
820859bfd8dSPatrick Delaunay 	}
821859bfd8dSPatrick Delaunay 
822859bfd8dSPatrick Delaunay 	return USBD_OK;
823859bfd8dSPatrick Delaunay }
824859bfd8dSPatrick Delaunay 
825859bfd8dSPatrick Delaunay /*
826859bfd8dSPatrick Delaunay  * register_platform
827859bfd8dSPatrick Delaunay  *         Register the USB device core.
828859bfd8dSPatrick Delaunay  * pdev: Device Handle
829859bfd8dSPatrick Delaunay  * plat_call_back: callback
830859bfd8dSPatrick Delaunay  * return : USBD Status
831859bfd8dSPatrick Delaunay  */
832859bfd8dSPatrick Delaunay enum usb_status register_platform(struct usb_handle *pdev,
833859bfd8dSPatrick Delaunay 			       const struct usb_desc *plat_call_back)
834859bfd8dSPatrick Delaunay {
835859bfd8dSPatrick Delaunay 	assert(pdev != NULL);
836859bfd8dSPatrick Delaunay 	assert(plat_call_back != NULL);
837859bfd8dSPatrick Delaunay 
838859bfd8dSPatrick Delaunay 	/* Save platform info in class resources */
839859bfd8dSPatrick Delaunay 	pdev->desc = plat_call_back;
840859bfd8dSPatrick Delaunay 
841859bfd8dSPatrick Delaunay 	return USBD_OK;
842859bfd8dSPatrick Delaunay }
843