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, ¶m)) {
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