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