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