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