From f0e4009c30d1597c756db4c03e97d3b75e730888 Mon Sep 17 00:00:00 2001 From: Wayne Lin Date: Fri, 15 May 2020 09:46:01 +0800 Subject: Fix rt_hw_inputcapture_isr public function name in header file. Fix miss-break in HWTIMER_CTRL_INFO_GET case. --- components/drivers/hwtimer/hwtimer.c | 1 + .../drivers/include/drivers/rt_inputcapture.h | 2 +- components/drivers/usb/usbdevice/SConscript | 2 +- components/drivers/usb/usbdevice/core/ud_core.c | 2237 -------------------- .../drivers/usb/usbdevice/core/usbdevice_core.c | 2237 ++++++++++++++++++++ components/drivers/usb/usbhost/SConscript | 2 +- components/drivers/usb/usbhost/core/uh_core.c | 576 ----- components/drivers/usb/usbhost/core/usbhost_core.c | 576 +++++ 8 files changed, 2817 insertions(+), 2816 deletions(-) delete mode 100644 components/drivers/usb/usbdevice/core/ud_core.c create mode 100644 components/drivers/usb/usbdevice/core/usbdevice_core.c delete mode 100644 components/drivers/usb/usbhost/core/uh_core.c create mode 100644 components/drivers/usb/usbhost/core/usbhost_core.c (limited to 'components') diff --git a/components/drivers/hwtimer/hwtimer.c b/components/drivers/hwtimer/hwtimer.c index 83a76c7b9d..3953919fae 100644 --- a/components/drivers/hwtimer/hwtimer.c +++ b/components/drivers/hwtimer/hwtimer.c @@ -255,6 +255,7 @@ static rt_err_t rt_hwtimer_control(struct rt_device *dev, int cmd, void *args) *((struct rt_hwtimer_info*)args) = *timer->info; } + break; case HWTIMER_CTRL_MODE_SET: { rt_hwtimer_mode_t *m; diff --git a/components/drivers/include/drivers/rt_inputcapture.h b/components/drivers/include/drivers/rt_inputcapture.h index 0cadf6444c..40cd55883d 100644 --- a/components/drivers/include/drivers/rt_inputcapture.h +++ b/components/drivers/include/drivers/rt_inputcapture.h @@ -48,7 +48,7 @@ struct rt_inputcapture_ops rt_err_t (*get_pulsewidth)(struct rt_inputcapture_device *inputcapture, rt_uint32_t *pulsewidth_us); }; -void rt_hw_capture_isr(struct rt_inputcapture_device *inputcapture, rt_bool_t level); +void rt_hw_inputcapture_isr(struct rt_inputcapture_device *inputcapture, rt_bool_t level); rt_err_t rt_device_inputcapture_register(struct rt_inputcapture_device *inputcapture, const char *name, diff --git a/components/drivers/usb/usbdevice/SConscript b/components/drivers/usb/usbdevice/SConscript index 876875f8bc..b6dfa8da10 100644 --- a/components/drivers/usb/usbdevice/SConscript +++ b/components/drivers/usb/usbdevice/SConscript @@ -3,7 +3,7 @@ from building import * cwd = GetCurrentDir() src = Split(""" -core/ud_core.c +core/usbdevice_core.c core/usbdevice.c """) diff --git a/components/drivers/usb/usbdevice/core/ud_core.c b/components/drivers/usb/usbdevice/core/ud_core.c deleted file mode 100644 index ef569d7bf2..0000000000 --- a/components/drivers/usb/usbdevice/core/ud_core.c +++ /dev/null @@ -1,2237 +0,0 @@ -/* - * Copyright (c) 2006-2018, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2012-10-01 Yi Qiu first version - * 2012-12-12 heyuanjie87 change endpoint and function handler - * 2012-12-30 heyuanjie87 change inferface handler - * 2013-04-26 aozima add DEVICEQUALIFIER support. - * 2013-07-25 Yi Qiu update for USB CV test - * 2017-11-15 ZYH fix ep0 transform error - */ - -#include -#include "drivers/usb_common.h" -#include "drivers/usb_device.h" - -static rt_list_t device_list; - -static rt_size_t rt_usbd_ep_write(udevice_t device, uep_t ep, void *buffer, rt_size_t size); -static rt_size_t rt_usbd_ep_read_prepare(udevice_t device, uep_t ep, void *buffer, rt_size_t size); -static rt_err_t rt_usbd_ep_assign(udevice_t device, uep_t ep); -rt_err_t rt_usbd_ep_unassign(udevice_t device, uep_t ep); - -/** - * This function will handle get_device_descriptor bRequest. - * - * @param device the usb device object. - * @param setup the setup bRequest. - * - * @return RT_EOK on successful. - */ -static rt_err_t _get_device_descriptor(struct udevice* device, ureq_t setup) -{ - rt_size_t size; - - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(setup != RT_NULL); - - RT_DEBUG_LOG(RT_DEBUG_USB, ("_get_device_descriptor\n")); - - /* device descriptor wLength should less than USB_DESC_LENGTH_DEVICE*/ - size = (setup->wLength > USB_DESC_LENGTH_DEVICE) ? - USB_DESC_LENGTH_DEVICE : setup->wLength; - - /* send device descriptor to endpoint 0 */ - rt_usbd_ep0_write(device, (rt_uint8_t*) &device->dev_desc, size); - - return RT_EOK; -} - -/** - * This function will handle get_config_descriptor bRequest. - * - * @param device the usb device object. - * @param setup the setup bRequest. - * - * @return RT_EOK on successful. - */ -static rt_err_t _get_config_descriptor(struct udevice* device, ureq_t setup) -{ - rt_size_t size; - ucfg_desc_t cfg_desc; - - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(setup != RT_NULL); - - RT_DEBUG_LOG(RT_DEBUG_USB, ("_get_config_descriptor\n")); - - cfg_desc = &device->curr_cfg->cfg_desc; - size = (setup->wLength > cfg_desc->wTotalLength) ? - cfg_desc->wTotalLength : setup->wLength; - - /* send configuration descriptor to endpoint 0 */ - rt_usbd_ep0_write(device, (rt_uint8_t*)cfg_desc, size); - - return RT_EOK; -} - -/** - * This function will handle get_string_descriptor bRequest. - * - * @param device the usb device object. - * @param setup the setup bRequest. - * - * @return RT_EOK on successful, -RT_ERROR on invalid bRequest. - */ -static rt_err_t _get_string_descriptor(struct udevice* device, ureq_t setup) -{ - struct ustring_descriptor str_desc; - rt_uint8_t index, i; - rt_uint32_t len; - - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(setup != RT_NULL); - - RT_DEBUG_LOG(RT_DEBUG_USB, ("_get_string_descriptor\n")); - - str_desc.type = USB_DESC_TYPE_STRING; - index = setup->wValue & 0xFF; - - if(index == 0xEE) - { - index = USB_STRING_OS_INDEX; - } - - if(index > USB_STRING_MAX) - { - rt_kprintf("unknown string index\n"); - rt_usbd_ep0_set_stall(device); - return -RT_ERROR; - } - else if(index == USB_STRING_LANGID_INDEX) - { - str_desc.bLength = 4; - str_desc.String[0] = 0x09; - str_desc.String[1] = 0x04; - } - else - { - len = rt_strlen(device->str[index]); - str_desc.bLength = len*2 + 2; - - for(i=0; istr[index][i]; - str_desc.String[i*2 + 1] = 0; - } - } - - if (setup->wLength > str_desc.bLength) - len = str_desc.bLength; - else - len = setup->wLength; - - /* send string descriptor to endpoint 0 */ - rt_usbd_ep0_write(device, (rt_uint8_t*)&str_desc, len); - - return RT_EOK; -} - -static rt_err_t _get_qualifier_descriptor(struct udevice* device, ureq_t setup) -{ - RT_DEBUG_LOG(RT_DEBUG_USB, ("_get_qualifier_descriptor\n")); - - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(setup != RT_NULL); - - if(device->dev_qualifier && device->dcd->device_is_hs) - { - /* send device qualifier descriptor to endpoint 0 */ - rt_usbd_ep0_write(device, (rt_uint8_t*)device->dev_qualifier, - sizeof(struct usb_qualifier_descriptor)); - } - else - { - rt_usbd_ep0_set_stall(device); - } - - return RT_EOK; -} - -/** - * This function will handle get_descriptor bRequest. - * - * @param device the usb device object. - * @param setup the setup bRequest. - * - * @return RT_EOK on successful. - */ -static rt_err_t _get_descriptor(struct udevice* device, ureq_t setup) -{ - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(setup != RT_NULL); - - if(setup->request_type == USB_REQ_TYPE_DIR_IN) - { - switch(setup->wValue >> 8) - { - case USB_DESC_TYPE_DEVICE: - _get_device_descriptor(device, setup); - break; - case USB_DESC_TYPE_CONFIGURATION: - _get_config_descriptor(device, setup); - break; - case USB_DESC_TYPE_STRING: - _get_string_descriptor(device, setup); - break; - case USB_DESC_TYPE_DEVICEQUALIFIER: - /* If a full-speed only device (with a device descriptor version number equal to 0200H) receives a - GetDescriptor() request for a device_qualifier, it must respond with a request error. The host must not make - a request for an other_speed_configuration descriptor unless it first successfully retrieves the - device_qualifier descriptor. */ - if(device->dcd->device_is_hs) - { - _get_qualifier_descriptor(device, setup); - } - else - { - rt_usbd_ep0_set_stall(device); - } - break; - case USB_DESC_TYPE_OTHERSPEED: - _get_config_descriptor(device, setup); - break; - default: - rt_kprintf("unsupported descriptor request\n"); - rt_usbd_ep0_set_stall(device); - break; - } - } - else - { - rt_kprintf("request direction error\n"); - rt_usbd_ep0_set_stall(device); - } - - return RT_EOK; -} - -/** - * This function will handle get_interface bRequest. - * - * @param device the usb device object. - * @param setup the setup bRequest. - * - * @return RT_EOK on successful. - */ -static rt_err_t _get_interface(struct udevice* device, ureq_t setup) -{ - rt_uint8_t value; - uintf_t intf; - ufunction_t func; - - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(setup != RT_NULL); - - RT_DEBUG_LOG(RT_DEBUG_USB, ("_get_interface\n")); - - if (device->state != USB_STATE_CONFIGURED) - { - rt_usbd_ep0_set_stall(device); - return -RT_ERROR; - } - - /* find the specified interface and its alternate setting */ - intf = rt_usbd_find_interface(device, setup->wIndex & 0xFF, &func); - value = intf->curr_setting->intf_desc->bAlternateSetting; - - /* send the interface alternate setting to endpoint 0*/ - rt_usbd_ep0_write(device, &value, 1); - - if (intf->handler) - { - intf->handler(func, setup); - } - - return RT_EOK; -} - -/** - * This function will handle set_interface bRequest. - * - * @param device the usb device object. - * @param setup the setup bRequest. - * - * @return RT_EOK on successful. - */ -static rt_err_t _set_interface(struct udevice* device, ureq_t setup) -{ - ufunction_t func; - uintf_t intf; - uep_t ep; - struct rt_list_node* i; - ualtsetting_t setting; - - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(setup != RT_NULL); - - RT_DEBUG_LOG(RT_DEBUG_USB, ("_set_interface\n")); - - if (device->state != USB_STATE_CONFIGURED) - { - rt_usbd_ep0_set_stall(device); - return -RT_ERROR; - } - - /* find the specified interface */ - intf = rt_usbd_find_interface(device, setup->wIndex & 0xFF, &func); - - /* set alternate setting to the interface */ - rt_usbd_set_altsetting(intf, setup->wValue & 0xFF); - setting = intf->curr_setting; - - /* start all endpoints of the interface alternate setting */ - for(i=setting->ep_list.next; i != &setting->ep_list; i=i->next) - { - ep = (uep_t)rt_list_entry(i, struct uendpoint, list); - dcd_ep_disable(device->dcd, ep); - dcd_ep_enable(device->dcd, ep); - } - dcd_ep0_send_status(device->dcd); - - if (intf->handler) - { - intf->handler(func, setup); - } - - return RT_EOK; -} - -/** - * This function will handle get_config bRequest. - * - * @param device the usb device object. - * @param setup the setup bRequest. - * - * @return RT_EOK on successful. - */ -static rt_err_t _get_config(struct udevice* device, ureq_t setup) -{ - rt_uint8_t value; - - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(setup != RT_NULL); - RT_ASSERT(device->curr_cfg != RT_NULL); - - RT_DEBUG_LOG(RT_DEBUG_USB, ("_get_config\n")); - - if (device->state == USB_STATE_CONFIGURED) - { - /* get current configuration */ - value = device->curr_cfg->cfg_desc.bConfigurationValue; - } - else - { - value = 0; - } - /* write the current configuration to endpoint 0 */ - rt_usbd_ep0_write(device, &value, 1); - - return RT_EOK; -} - -/** - * This function will handle set_config bRequest. - * - * @param device the usb device object. - * @param setup the setup bRequest. - * - * @return RT_EOK on successful. - */ -static rt_err_t _set_config(struct udevice* device, ureq_t setup) -{ - struct rt_list_node *i, *j, *k; - uconfig_t cfg; - uintf_t intf; - ualtsetting_t setting; - uep_t ep; - - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(setup != RT_NULL); - - RT_DEBUG_LOG(RT_DEBUG_USB, ("_set_config\n")); - - if (setup->wValue > device->dev_desc.bNumConfigurations) - { - rt_usbd_ep0_set_stall(device); - return -RT_ERROR; - } - - if (setup->wValue == 0) - { - RT_DEBUG_LOG(RT_DEBUG_USB, ("address state\n")); - device->state = USB_STATE_ADDRESS; - - goto _exit; - } - - /* set current configuration */ - rt_usbd_set_config(device, setup->wValue); - cfg = device->curr_cfg; - - for (i=cfg->func_list.next; i!=&cfg->func_list; i=i->next) - { - /* run all functiones and their endpoints in the configuration */ - ufunction_t func = (ufunction_t)rt_list_entry(i, struct ufunction, list); - for(j=func->intf_list.next; j!=&func->intf_list; j=j->next) - { - intf = (uintf_t)rt_list_entry(j, struct uinterface, list); - setting = intf->curr_setting; - for(k=setting->ep_list.next; k != &setting->ep_list; k=k->next) - { - ep = (uep_t)rt_list_entry(k, struct uendpoint, list); - - /* first disable then enable an endpoint */ - dcd_ep_disable(device->dcd, ep); - dcd_ep_enable(device->dcd, ep); - } - } - /* after enabled endpoints, then enable function */ - FUNC_ENABLE(func); - } - - device->state = USB_STATE_CONFIGURED; - -_exit: - /* issue status stage */ - dcd_ep0_send_status(device->dcd); - - return RT_EOK; -} - -/** - * This function will handle set_address bRequest. - * - * @param device the usb device object. - * @param setup the setup bRequest. - * - * @return RT_EOK on successful. - */ -static rt_err_t _set_address(struct udevice* device, ureq_t setup) -{ - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(setup != RT_NULL); - - /* set address in device control driver */ - dcd_set_address(device->dcd, setup->wValue); - - /* issue status stage */ - dcd_ep0_send_status(device->dcd); - - RT_DEBUG_LOG(RT_DEBUG_USB, ("_set_address\n")); - - device->state = USB_STATE_ADDRESS; - - return RT_EOK; -} - -/** - * This function will handle standard bRequest to - * interface that defined in function-specifics - * - * @param device the usb device object. - * @param setup the setup bRequest. - * - * @return RT_EOK on successful. - */ -static rt_err_t _request_interface(struct udevice* device, ureq_t setup) -{ - uintf_t intf; - ufunction_t func; - rt_err_t ret; - - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(setup != RT_NULL); - - RT_DEBUG_LOG(RT_DEBUG_USB, ("_request_interface\n")); - - intf = rt_usbd_find_interface(device, setup->wIndex & 0xFF, &func); - if (intf != RT_NULL) - { - ret = intf->handler(func, setup); - } - else - { - ret = -RT_ERROR; - } - - return ret; -} - -/** - * This function will handle standard bRequest. - * - * @param device the usb device object. - * @param setup the setup bRequest. - * - * @return RT_EOK on successful. - */ -static rt_err_t _standard_request(struct udevice* device, ureq_t setup) -{ - udcd_t dcd; - rt_uint16_t value = 0; - - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(setup != RT_NULL); - - dcd = device->dcd; - - switch(setup->request_type & USB_REQ_TYPE_RECIPIENT_MASK) - { - case USB_REQ_TYPE_DEVICE: - switch(setup->bRequest) - { - case USB_REQ_GET_STATUS: - rt_usbd_ep0_write(device, &value, 2); - break; - case USB_REQ_CLEAR_FEATURE: - rt_usbd_clear_feature(device, setup->wValue, setup->wIndex); - dcd_ep0_send_status(dcd); - break; - case USB_REQ_SET_FEATURE: - rt_usbd_set_feature(device, setup->wValue, setup->wIndex); - break; - case USB_REQ_SET_ADDRESS: - _set_address(device, setup); - break; - case USB_REQ_GET_DESCRIPTOR: - _get_descriptor(device, setup); - break; - case USB_REQ_SET_DESCRIPTOR: - rt_usbd_ep0_set_stall(device); - break; - case USB_REQ_GET_CONFIGURATION: - _get_config(device, setup); - break; - case USB_REQ_SET_CONFIGURATION: - _set_config(device, setup); - break; - default: - rt_kprintf("unknown device request\n"); - rt_usbd_ep0_set_stall(device); - break; - } - break; - case USB_REQ_TYPE_INTERFACE: - switch(setup->bRequest) - { - case USB_REQ_GET_INTERFACE: - _get_interface(device, setup); - break; - case USB_REQ_SET_INTERFACE: - _set_interface(device, setup); - break; - default: - if (_request_interface(device, setup) != RT_EOK) - { - rt_kprintf("unknown interface request\n"); - rt_usbd_ep0_set_stall(device); - return - RT_ERROR; - } - else - break; - } - break; - case USB_REQ_TYPE_ENDPOINT: - switch(setup->bRequest) - { - case USB_REQ_GET_STATUS: - { - uep_t ep; - - ep = rt_usbd_find_endpoint(device, RT_NULL, setup->wIndex); - value = ep->stalled; - rt_usbd_ep0_write(device, &value, 2); - } - break; - case USB_REQ_CLEAR_FEATURE: - { - uep_t ep; - uio_request_t req; - struct rt_list_node *node; - - ep = rt_usbd_find_endpoint(device, RT_NULL, setup->wIndex); - if(USB_EP_HALT == setup->wValue && ep->stalled == RT_TRUE) - { - rt_usbd_clear_feature(device, setup->wValue, setup->wIndex); - dcd_ep0_send_status(dcd); - ep->stalled = RT_FALSE; - - for (node = ep->request_list.next; node != &ep->request_list; node = node->next) - { - req = (uio_request_t)rt_list_entry(node, struct uio_request, list); - rt_usbd_io_request(device, ep, req); - RT_DEBUG_LOG(RT_DEBUG_USB, ("fired a request\n")); - } - - rt_list_init(&ep->request_list); - } - } - break; - case USB_REQ_SET_FEATURE: - { - uep_t ep; - - if(USB_EP_HALT == setup->wValue) - { - ep = rt_usbd_find_endpoint(device, RT_NULL, setup->wIndex); - ep->stalled = RT_TRUE; - rt_usbd_set_feature(device, setup->wValue, setup->wIndex); - dcd_ep0_send_status(dcd); - } - } - break; - case USB_REQ_SYNCH_FRAME: - break; - default: - rt_kprintf("unknown endpoint request\n"); - rt_usbd_ep0_set_stall(device); - break; - } - break; - case USB_REQ_TYPE_OTHER: - rt_kprintf("unknown other type request\n"); - rt_usbd_ep0_set_stall(device); - break; - default: - rt_kprintf("unknown type request\n"); - rt_usbd_ep0_set_stall(device); - break; - } - - return RT_EOK; -} - -/** - * This function will handle function bRequest. - * - * @param device the usb device object. - * @param setup the setup bRequest. - * - * @return RT_EOK on successful, -RT_ERROR on invalid bRequest. - */ -static rt_err_t _function_request(udevice_t device, ureq_t setup) -{ - uintf_t intf; - ufunction_t func; - - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(setup != RT_NULL); - - /* verify bRequest wValue */ - if(setup->wIndex > device->curr_cfg->cfg_desc.bNumInterfaces) - { - rt_usbd_ep0_set_stall(device); - return -RT_ERROR; - } - - switch(setup->request_type & USB_REQ_TYPE_RECIPIENT_MASK) - { - case USB_REQ_TYPE_INTERFACE: - intf = rt_usbd_find_interface(device, setup->wIndex & 0xFF, &func); - if(intf == RT_NULL) - { - rt_kprintf("unkwown interface request\n"); - rt_usbd_ep0_set_stall(device); - } - else - { - intf->handler(func, setup); - } - break; - case USB_REQ_TYPE_ENDPOINT: - break; - default: - rt_kprintf("unknown function request type\n"); - rt_usbd_ep0_set_stall(device); - break; - } - - return RT_EOK; -} -static rt_err_t _vendor_request(udevice_t device, ureq_t setup) -{ - static rt_uint8_t * usb_comp_id_desc = RT_NULL; - static rt_uint32_t usb_comp_id_desc_size = 0; - usb_os_func_comp_id_desc_t func_comp_id_desc; - uintf_t intf; - ufunction_t func; - switch(setup->bRequest) - { - case 'A': - switch(setup->wIndex) - { - case 0x04: - if(rt_list_len(&device->os_comp_id_desc->func_desc) == 0) - { - rt_usbd_ep0_set_stall(device); - return RT_EOK; - } - if(usb_comp_id_desc == RT_NULL) - { - rt_uint8_t * pusb_comp_id_desc; - rt_list_t *p; - usb_comp_id_desc_size = sizeof(struct usb_os_header_comp_id_descriptor) + - (sizeof(struct usb_os_function_comp_id_descriptor)-sizeof(rt_list_t))*rt_list_len(&device->os_comp_id_desc->func_desc); - - usb_comp_id_desc = (rt_uint8_t *)rt_malloc(usb_comp_id_desc_size); - RT_ASSERT(usb_comp_id_desc != RT_NULL); - device->os_comp_id_desc->head_desc.dwLength = usb_comp_id_desc_size; - pusb_comp_id_desc = usb_comp_id_desc; - rt_memcpy((void *)pusb_comp_id_desc,(void *)&device->os_comp_id_desc->head_desc,sizeof(struct usb_os_header_comp_id_descriptor)); - pusb_comp_id_desc += sizeof(struct usb_os_header_comp_id_descriptor); - - for (p = device->os_comp_id_desc->func_desc.next; p != &device->os_comp_id_desc->func_desc; p = p->next) - { - func_comp_id_desc = rt_list_entry(p,struct usb_os_function_comp_id_descriptor,list); - rt_memcpy(pusb_comp_id_desc,(void *)&func_comp_id_desc->bFirstInterfaceNumber, - sizeof(struct usb_os_function_comp_id_descriptor)-sizeof(rt_list_t)); - pusb_comp_id_desc += sizeof(struct usb_os_function_comp_id_descriptor)-sizeof(rt_list_t); - } - } - rt_usbd_ep0_write(device, (void*)usb_comp_id_desc, setup->wLength); - break; - case 0x05: - intf = rt_usbd_find_interface(device, setup->wValue & 0xFF, &func); - if(intf != RT_NULL) - { - intf->handler(func, setup); - } - break; - } - - break; - } - return RT_EOK; -} -static rt_err_t _dump_setup_packet(ureq_t setup) -{ - RT_DEBUG_LOG(RT_DEBUG_USB, ("[\n")); - RT_DEBUG_LOG(RT_DEBUG_USB, (" setup_request : 0x%x\n", - setup->request_type)); - RT_DEBUG_LOG(RT_DEBUG_USB, (" value : 0x%x\n", setup->wValue)); - RT_DEBUG_LOG(RT_DEBUG_USB, (" length : 0x%x\n", setup->wLength)); - RT_DEBUG_LOG(RT_DEBUG_USB, (" index : 0x%x\n", setup->wIndex)); - RT_DEBUG_LOG(RT_DEBUG_USB, (" request : 0x%x\n", setup->bRequest)); - RT_DEBUG_LOG(RT_DEBUG_USB, ("]\n")); - - return RT_EOK; -} - -/** - * This function will handle setup bRequest. - * - * @param device the usb device object. - * @param setup the setup bRequest. - * - * @return RT_EOK on successful, -RT_ERROR on invalid bRequest. - */ -static rt_err_t _setup_request(udevice_t device, ureq_t setup) -{ - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(setup != RT_NULL); - - _dump_setup_packet(setup); - - switch((setup->request_type & USB_REQ_TYPE_MASK)) - { - case USB_REQ_TYPE_STANDARD: - _standard_request(device, setup); - break; - case USB_REQ_TYPE_CLASS: - _function_request(device, setup); - break; - case USB_REQ_TYPE_VENDOR: - _vendor_request(device, setup); - break; - default: - rt_kprintf("unknown setup request type\n"); - rt_usbd_ep0_set_stall(device); - return -RT_ERROR; - } - - return RT_EOK; -} - -/** - * This function will hanle data notify event. - * - * @param device the usb device object. - * @param ep_msg the endpoint message. - * - * @return RT_EOK. - */ -static rt_err_t _data_notify(udevice_t device, struct ep_msg* ep_msg) -{ - uep_t ep; - ufunction_t func; - rt_size_t size = 0; - - RT_ASSERT(device != RT_NULL); - RT_ASSERT(ep_msg != RT_NULL); - - if (device->state != USB_STATE_CONFIGURED) - { - return -RT_ERROR; - } - - ep = rt_usbd_find_endpoint(device, &func, ep_msg->ep_addr); - if(ep == RT_NULL) - { - rt_kprintf("invalid endpoint\n"); - return -RT_ERROR; - } - - if(EP_ADDRESS(ep) & USB_DIR_IN) - { - size = ep_msg->size; - if(ep->request.remain_size >= EP_MAXPACKET(ep)) - { - dcd_ep_write(device->dcd, EP_ADDRESS(ep), ep->request.buffer, EP_MAXPACKET(ep)); - ep->request.remain_size -= EP_MAXPACKET(ep); - ep->request.buffer += EP_MAXPACKET(ep); - } - else if(ep->request.remain_size > 0) - { - dcd_ep_write(device->dcd, EP_ADDRESS(ep), ep->request.buffer, ep->request.remain_size); - ep->request.remain_size = 0; - } - else - { - EP_HANDLER(ep, func, size); - } - } - else - { - size = ep_msg->size; - if(ep->request.remain_size == 0) - { - return RT_EOK; - } - - if(size == 0) - { - size = dcd_ep_read(device->dcd, EP_ADDRESS(ep), ep->request.buffer); - } - ep->request.remain_size -= size; - ep->request.buffer += size; - - if(ep->request.req_type == UIO_REQUEST_READ_BEST) - { - EP_HANDLER(ep, func, size); - } - else if(ep->request.remain_size == 0) - { - EP_HANDLER(ep, func, ep->request.size); - } - else - { - dcd_ep_read_prepare(device->dcd, EP_ADDRESS(ep), ep->request.buffer, ep->request.remain_size > EP_MAXPACKET(ep) ? EP_MAXPACKET(ep) : ep->request.remain_size); - } - } - - return RT_EOK; -} - -static rt_err_t _ep0_out_notify(udevice_t device, struct ep_msg* ep_msg) -{ - uep_t ep0; - rt_size_t size; - - RT_ASSERT(device != RT_NULL); - RT_ASSERT(ep_msg != RT_NULL); - RT_ASSERT(device->dcd != RT_NULL); - - ep0 = &device->dcd->ep0; - size = ep_msg->size; - - if(ep0->request.remain_size == 0) - { - return RT_EOK; - } - if(size == 0) - { - size = dcd_ep_read(device->dcd, EP0_OUT_ADDR, ep0->request.buffer); - if(size == 0) - { - return RT_EOK; - } - } - - ep0->request.remain_size -= size; - ep0->request.buffer += size; - if(ep0->request.remain_size == 0) - { - /* invoke callback */ - if(ep0->rx_indicate != RT_NULL) - { - ep0->rx_indicate(device, size); - } - } - else - { - rt_usbd_ep0_read(device, ep0->request.buffer, ep0->request.remain_size,ep0->rx_indicate); - } - - return RT_EOK; -} - -/** - * This function will notity sof event to all of function. - * - * @param device the usb device object. - * - * @return RT_EOK. - */ -static rt_err_t _sof_notify(udevice_t device) -{ - struct rt_list_node *i; - ufunction_t func; - - RT_ASSERT(device != RT_NULL); - - /* to notity every function that sof event comes */ - for (i=device->curr_cfg->func_list.next; - i!=&device->curr_cfg->func_list; i=i->next) - { - func = (ufunction_t)rt_list_entry(i, struct ufunction, list); - if(func->ops->sof_handler != RT_NULL) - func->ops->sof_handler(func); - } - - return RT_EOK; -} - -/** - * This function will disable all USB functions. - * - * @param device the usb device object. - * - * @return RT_EOK. - */ -static rt_err_t _stop_notify(udevice_t device) -{ - struct rt_list_node *i; - ufunction_t func; - - RT_ASSERT(device != RT_NULL); - - /* to notity every function */ - for (i = device->curr_cfg->func_list.next; - i != &device->curr_cfg->func_list; - i = i->next) - { - func = (ufunction_t)rt_list_entry(i, struct ufunction, list); - FUNC_DISABLE(func); - } - - return RT_EOK; -} - -static rt_size_t rt_usbd_ep_write(udevice_t device, uep_t ep, void *buffer, rt_size_t size) -{ - rt_uint16_t maxpacket; - - RT_ASSERT(device != RT_NULL); - RT_ASSERT(device->dcd != RT_NULL); - RT_ASSERT(ep != RT_NULL); - - rt_enter_critical(); - maxpacket = EP_MAXPACKET(ep); - if(ep->request.remain_size >= maxpacket) - { - dcd_ep_write(device->dcd, EP_ADDRESS(ep), ep->request.buffer, maxpacket); - ep->request.remain_size -= maxpacket; - ep->request.buffer += maxpacket; - } - else - { - dcd_ep_write(device->dcd, EP_ADDRESS(ep), ep->request.buffer, - ep->request.remain_size); - ep->request.remain_size = 0; - } - rt_exit_critical(); - return size; -} - -static rt_size_t rt_usbd_ep_read_prepare(udevice_t device, uep_t ep, void *buffer, rt_size_t size) -{ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(device->dcd != RT_NULL); - RT_ASSERT(ep != RT_NULL); - RT_ASSERT(buffer != RT_NULL); - RT_ASSERT(ep->ep_desc != RT_NULL); - - return dcd_ep_read_prepare(device->dcd, EP_ADDRESS(ep), buffer, size > EP_MAXPACKET(ep) ? EP_MAXPACKET(ep) : size); -} - -/** - * This function will create an usb device object. - * - * @param ustring the usb string array to contain string descriptor. - * - * @return an usb device object on success, RT_NULL on fail. - */ -udevice_t rt_usbd_device_new(void) -{ - udevice_t udevice; - - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_device_new\n")); - - /* allocate memory for the object */ - udevice = (udevice_t)rt_malloc(sizeof(struct udevice)); - if(udevice == RT_NULL) - { - rt_kprintf("alloc memory failed\n"); - return RT_NULL; - } - rt_memset(udevice, 0, sizeof(struct udevice)); - - /* to initialize configuration list */ - rt_list_init(&udevice->cfg_list); - - /* insert the device object to device list */ - rt_list_insert_before(&device_list, &udevice->list); - - return udevice; -} - -/** - * This function will set usb device string description. - * - * @param device the usb device object. - * @param ustring pointer to string pointer array. - * - * @return RT_EOK. - */ -rt_err_t rt_usbd_device_set_string(udevice_t device, const char** ustring) -{ - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(ustring != RT_NULL); - - /* set string descriptor array to the device object */ - device->str = ustring; - - return RT_EOK; -} - -rt_err_t rt_usbd_device_set_os_comp_id_desc(udevice_t device, usb_os_comp_id_desc_t os_comp_id_desc) -{ - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(os_comp_id_desc != RT_NULL); - - /* set string descriptor array to the device object */ - device->os_comp_id_desc = os_comp_id_desc; - rt_list_init(&device->os_comp_id_desc->func_desc); - return RT_EOK; -} - -rt_err_t rt_usbd_device_set_qualifier(udevice_t device, struct usb_qualifier_descriptor* qualifier) -{ - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(qualifier != RT_NULL); - - device->dev_qualifier = qualifier; - - return RT_EOK; -} - -/** - * This function will set an usb controller driver to a device. - * - * @param device the usb device object. - * @param dcd the usb device controller driver. - * - * @return RT_EOK on successful. - */ -rt_err_t rt_usbd_device_set_controller(udevice_t device, udcd_t dcd) -{ - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(dcd != RT_NULL); - - /* set usb device controller driver to the device */ - device->dcd = dcd; - - return RT_EOK; -} - -/** - * This function will set an usb device descriptor to a device. - * - * @param device the usb device object. - * @param dev_desc the usb device descriptor. - * - * @return RT_EOK on successful. - */ -rt_err_t rt_usbd_device_set_descriptor(udevice_t device, udev_desc_t dev_desc) -{ - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(dev_desc != RT_NULL); - - /* copy the usb device descriptor to the device */ - rt_memcpy((void *)&device->dev_desc, (void *)dev_desc, USB_DESC_LENGTH_DEVICE); - - return RT_EOK; -} - -/** - * This function will create an usb configuration object. - * - * @param none. - * - * @return an usb configuration object. - */ -uconfig_t rt_usbd_config_new(void) -{ - uconfig_t cfg; - - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_config_new\n")); - - /* allocate memory for the object */ - cfg = (uconfig_t)rt_malloc(sizeof(struct uconfig)); - if(cfg == RT_NULL) - { - rt_kprintf("alloc memory failed\n"); - return RT_NULL; - } - rt_memset(cfg, 0, sizeof(struct uconfig)); - - /* set default wValue */ - cfg->cfg_desc.bLength = USB_DESC_LENGTH_CONFIG; - cfg->cfg_desc.type = USB_DESC_TYPE_CONFIGURATION; - cfg->cfg_desc.wTotalLength = USB_DESC_LENGTH_CONFIG; - cfg->cfg_desc.bmAttributes = 0xC0; - cfg->cfg_desc.MaxPower = 0x32; - - /* to initialize function object list */ - rt_list_init(&cfg->func_list); - - return cfg; -} - -/** - * This function will create an usb interface object. - * - * @param device the usb device object. - * @handler the callback handler of object - * - * @return an usb interface object on success, RT_NULL on fail. - */ -uintf_t rt_usbd_interface_new(udevice_t device, uintf_handler_t handler) -{ - uintf_t intf; - - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_interface_new\n")); - - /* parameter check */ - RT_ASSERT(device != RT_NULL); - - /* allocate memory for the object */ - intf = (uintf_t)rt_malloc(sizeof(struct uinterface)); - if(intf == RT_NULL) - { - rt_kprintf("alloc memory failed\n"); - return RT_NULL; - } - intf->intf_num = device->nr_intf; - device->nr_intf++; - intf->handler = handler; - intf->curr_setting = RT_NULL; - - /* to initialize the alternate setting object list */ - rt_list_init(&intf->setting_list); - - return intf; -} - -/** - * This function will create an usb alternate setting object. - * - * @param intf_desc the interface descriptor. - * @desc_size the size of the interface descriptor. - * - * @return an usb alternate setting object on success, RT_NULL on fail. - */ -ualtsetting_t rt_usbd_altsetting_new(rt_size_t desc_size) -{ - ualtsetting_t setting; - - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_altsetting_new\n")); - - /* parameter check */ - RT_ASSERT(desc_size > 0); - - /* allocate memory for the object */ - setting = (ualtsetting_t)rt_malloc(sizeof(struct ualtsetting)); - if(setting == RT_NULL) - { - rt_kprintf("alloc memory failed\n"); - return RT_NULL; - } - /* allocate memory for the desc */ - setting->desc = rt_malloc(desc_size); - if (setting->desc == RT_NULL) - { - rt_kprintf("alloc desc memory failed\n"); - rt_free(setting); - return RT_NULL; - } - - setting->desc_size = desc_size; - setting->intf_desc = RT_NULL; - - /* to initialize endpoint list */ - rt_list_init(&setting->ep_list); - - return setting; -} - -/** - * This function will config an desc in alternate setting object. - * - * @param setting the altsetting to be config. - * @param desc use it to init desc in setting. - * @param intf_pos the offset of interface descriptor in desc. - * - * @return RT_EOK. - */ -rt_err_t rt_usbd_altsetting_config_descriptor(ualtsetting_t setting, const void* desc, rt_off_t intf_pos) -{ - RT_ASSERT(setting != RT_NULL); - RT_ASSERT(setting->desc !=RT_NULL); - - rt_memcpy(setting->desc, desc, setting->desc_size); - setting->intf_desc = (uintf_desc_t)((char*)setting->desc + intf_pos); - - return RT_EOK; -} - -/** - * This function will create an usb function object. - * - * @param device the usb device object. - * @param dev_desc the device descriptor. - * @param ops the operation set. - * - * @return an usb function object on success, RT_NULL on fail. - */ -ufunction_t rt_usbd_function_new(udevice_t device, udev_desc_t dev_desc, - ufunction_ops_t ops) -{ - ufunction_t func; - - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_function_new\n")); - - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(dev_desc != RT_NULL); - - /* allocate memory for the object */ - func = (ufunction_t)rt_malloc(sizeof(struct ufunction)); - if(func == RT_NULL) - { - rt_kprintf("alloc memory failed\n"); - return RT_NULL; - } - func->dev_desc = dev_desc; - func->ops = ops; - func->device = device; - func->enabled = RT_FALSE; - - /* to initialize interface list */ - rt_list_init(&func->intf_list); - - return func; -} - -/** - * This function will create an usb endpoint object. - * - * @param ep_desc the endpoint descriptor. - * @handler the callback handler of object - * - * @return an usb endpoint object on success, RT_NULL on fail. - */ -uep_t rt_usbd_endpoint_new(uep_desc_t ep_desc, udep_handler_t handler) -{ - uep_t ep; - - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_endpoint_new\n")); - - /* parameter check */ - RT_ASSERT(ep_desc != RT_NULL); - - /* allocate memory for the object */ - ep = (uep_t)rt_malloc(sizeof(struct uendpoint)); - if(ep == RT_NULL) - { - rt_kprintf("alloc memory failed\n"); - return RT_NULL; - } - ep->ep_desc = ep_desc; - ep->handler = handler; - ep->buffer = RT_NULL; - ep->stalled = RT_FALSE; - rt_list_init(&ep->request_list); - - return ep; -} - -/** - * This function will find an usb device object. - * - * @dcd usd device controller driver. - * - * @return an usb device object on found or RT_NULL on not found. - */ -udevice_t rt_usbd_find_device(udcd_t dcd) -{ - struct rt_list_node* node; - udevice_t device; - - /* parameter check */ - RT_ASSERT(dcd != RT_NULL); - - /* search a device in the the device list */ - for (node = device_list.next; node != &device_list; node = node->next) - { - device = (udevice_t)rt_list_entry(node, struct udevice, list); - if(device->dcd == dcd) return device; - } - - rt_kprintf("can't find device\n"); - return RT_NULL; -} - -/** - * This function will find an usb configuration object. - * - * @param device the usb device object. - * @param wValue the configuration number. - * - * @return an usb configuration object on found or RT_NULL on not found. - */ -uconfig_t rt_usbd_find_config(udevice_t device, rt_uint8_t value) -{ - struct rt_list_node* node; - uconfig_t cfg = RT_NULL; - - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_find_config\n")); - - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(value <= device->dev_desc.bNumConfigurations); - - /* search a configration in the the device */ - for (node = device->cfg_list.next; node != &device->cfg_list; node = node->next) - { - cfg = (uconfig_t)rt_list_entry(node, struct udevice, list); - if(cfg->cfg_desc.bConfigurationValue == value) - { - return cfg; - } - } - - rt_kprintf("can't find configuration %d\n", value); - return RT_NULL; -} - -/** - * This function will find an usb interface object. - * - * @param device the usb device object. - * @param wValue the interface number. - * - * @return an usb configuration object on found or RT_NULL on not found. - */ -uintf_t rt_usbd_find_interface(udevice_t device, rt_uint8_t value, ufunction_t *pfunc) -{ - struct rt_list_node *i, *j; - ufunction_t func; - uintf_t intf; - - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_find_interface\n")); - - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(value < device->nr_intf); - - /* search an interface in the current configuration */ - for (i=device->curr_cfg->func_list.next; - i!=&device->curr_cfg->func_list; i=i->next) - { - func = (ufunction_t)rt_list_entry(i, struct ufunction, list); - for(j=func->intf_list.next; j!=&func->intf_list; j=j->next) - { - intf = (uintf_t)rt_list_entry(j, struct uinterface, list); - if(intf->intf_num == value) - { - if (pfunc != RT_NULL) - *pfunc = func; - return intf; - } - } - } - - rt_kprintf("can't find interface %d\n", value); - return RT_NULL; -} - -/** - * This function will find an usb interface alternate setting object. - * - * @param device the usb device object. - * @param wValue the alternate setting number. - * - * @return an usb interface alternate setting object on found or RT_NULL on not found. - */ -ualtsetting_t rt_usbd_find_altsetting(uintf_t intf, rt_uint8_t value) -{ - struct rt_list_node *i; - ualtsetting_t setting; - - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_find_altsetting\n")); - - /* parameter check */ - RT_ASSERT(intf != RT_NULL); - - if(intf->curr_setting != RT_NULL) - { - /* if the wValue equal to the current alternate setting, then do not search */ - if(intf->curr_setting->intf_desc->bAlternateSetting == value) - return intf->curr_setting; - } - - /* search a setting in the alternate setting list */ - for(i=intf->setting_list.next; i!=&intf->setting_list; i=i->next) - { - setting =(ualtsetting_t)rt_list_entry(i, struct ualtsetting, list); - if(setting->intf_desc->bAlternateSetting == value) - return setting; - } - - rt_kprintf("can't find alternate setting %d\n", value); - return RT_NULL; -} - -/** - * This function will find an usb endpoint object. - * - * @param device the usb device object. - * @param ep_addr endpoint address. - * - * @return an usb endpoint object on found or RT_NULL on not found. - */ -uep_t rt_usbd_find_endpoint(udevice_t device, ufunction_t* pfunc, rt_uint8_t ep_addr) -{ - uep_t ep; - struct rt_list_node *i, *j, *k; - ufunction_t func; - uintf_t intf; - - /* parameter check */ - RT_ASSERT(device != RT_NULL); - - /* search a endpoint in the current configuration */ - for (i=device->curr_cfg->func_list.next; i!=&device->curr_cfg->func_list; i=i->next) - { - func = (ufunction_t)rt_list_entry(i, struct ufunction, list); - for(j=func->intf_list.next; j!=&func->intf_list; j=j->next) - { - intf = (uintf_t)rt_list_entry(j, struct uinterface, list); - for(k=intf->curr_setting->ep_list.next; - k!=&intf->curr_setting->ep_list; k=k->next) - { - ep = (uep_t)rt_list_entry(k, struct uendpoint, list); - if(EP_ADDRESS(ep) == ep_addr) - { - if (pfunc != RT_NULL) - *pfunc = func; - return ep; - } - } - } - } - - rt_kprintf("can't find endpoint 0x%x\n", ep_addr); - return RT_NULL; -} - -/** - * This function will add a configuration to an usb device. - * - * @param device the usb device object. - * @param cfg the configuration object. - * - * @return RT_EOK. - */ -rt_err_t rt_usbd_device_add_config(udevice_t device, uconfig_t cfg) -{ - struct rt_list_node *i, *j, *k, *m; - ufunction_t func; - uintf_t intf; - ualtsetting_t altsetting; - uep_t ep; - - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_device_add_config\n")); - - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(cfg != RT_NULL); - - /* set configuration number to the configuration descriptor */ - cfg->cfg_desc.bConfigurationValue = device->dev_desc.bNumConfigurations + 1; - device->dev_desc.bNumConfigurations++; - - for (i=cfg->func_list.next; i!=&cfg->func_list; i=i->next) - { - func = (ufunction_t)rt_list_entry(i, struct ufunction, list); - - for(j=func->intf_list.next; j!=&func->intf_list; j=j->next) - { - intf = (uintf_t)rt_list_entry(j, struct uinterface, list); - cfg->cfg_desc.bNumInterfaces++; - - for(k=intf->setting_list.next; k!=&intf->setting_list;k=k->next) - { - altsetting = (ualtsetting_t)rt_list_entry(k, struct ualtsetting, list); - - /* allocate address for every endpoint in the interface alternate setting */ - for(m=altsetting->ep_list.next; m!=&altsetting->ep_list; m=m->next) - { - ep = (uep_t)rt_list_entry(m, struct uendpoint, list); - if(rt_usbd_ep_assign(device, ep) != RT_EOK) - { - rt_kprintf("endpoint assign error\n"); - } - } - - /* construct complete configuration descriptor */ - rt_memcpy((void*)&cfg->cfg_desc.data[cfg->cfg_desc.wTotalLength - USB_DESC_LENGTH_CONFIG], - (void*)altsetting->desc, - altsetting->desc_size); - cfg->cfg_desc.wTotalLength += altsetting->desc_size; - } - } - } - - /* insert the configuration to the list */ - rt_list_insert_before(&device->cfg_list, &cfg->list); - - return RT_EOK; -} - -/** - * This function will add a function to a configuration. - * - * @param cfg the configuration object. - * @param func the function object. - * - * @return RT_EOK. - */ -rt_err_t rt_usbd_config_add_function(uconfig_t cfg, ufunction_t func) -{ - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_config_add_function\n")); - - /* parameter check */ - RT_ASSERT(cfg != RT_NULL); - RT_ASSERT(func != RT_NULL); - - /* insert the function to the list */ - rt_list_insert_before(&cfg->func_list, &func->list); - - return RT_EOK; -} - -/** - * This function will add an interface to a function. - * - * @param func the function object. - * @param intf the interface object. - * - * @return RT_EOK. - */ -rt_err_t rt_usbd_function_add_interface(ufunction_t func, uintf_t intf) -{ - - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_function_add_interface\n")); - - /* parameter check */ - RT_ASSERT(func != RT_NULL); - RT_ASSERT(intf != RT_NULL); - - /* insert the interface to the list */ - rt_list_insert_before(&func->intf_list, &intf->list); - - return RT_EOK; -} - -/** - * This function will add an alternate setting to an interface. - * - * @param intf the interface object. - * @param setting the alternate setting object. - * - * @return RT_EOK. - */ -rt_err_t rt_usbd_interface_add_altsetting(uintf_t intf, ualtsetting_t setting) -{ - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_interface_add_altsetting\n")); - - /* parameter check */ - RT_ASSERT(intf != RT_NULL); - RT_ASSERT(setting != RT_NULL); - - setting->intf_desc->bInterfaceNumber = intf->intf_num; - - /* insert the alternate setting to the list */ - rt_list_insert_before(&intf->setting_list, &setting->list); - - return RT_EOK; -} - -/** - * This function will add an endpoint to an alternate setting. - * - * @param setting the alternate setting object. - * @param ep the endpoint object. - * - * @return RT_EOK. - */ -rt_err_t rt_usbd_altsetting_add_endpoint(ualtsetting_t setting, uep_t ep) -{ - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_altsetting_add_endpoint\n")); - - /* parameter check */ - RT_ASSERT(setting != RT_NULL); - RT_ASSERT(ep != RT_NULL); - - /* insert the endpoint to the list */ - rt_list_insert_before(&setting->ep_list, &ep->list); - - return RT_EOK; -} - -rt_err_t rt_usbd_os_comp_id_desc_add_os_func_comp_id_desc(usb_os_comp_id_desc_t os_comp_id_desc, usb_os_func_comp_id_desc_t os_func_comp_id_desc) -{ - RT_ASSERT(os_comp_id_desc != RT_NULL); - RT_ASSERT(os_func_comp_id_desc != RT_NULL); - rt_list_insert_before(&os_comp_id_desc->func_desc, &os_func_comp_id_desc->list); - os_comp_id_desc->head_desc.bCount++; - return RT_EOK; -} - -/** - * This function will set an alternate setting for an interface. - * - * @param intf_desc the interface descriptor. - * @param wValue the alternate setting number. - * - * @return RT_EOK. - */ -rt_err_t rt_usbd_set_altsetting(uintf_t intf, rt_uint8_t value) -{ - ualtsetting_t setting; - - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_set_altsetting\n")); - - /* parameter check */ - RT_ASSERT(intf != RT_NULL); - - /* find an alternate setting */ - setting = rt_usbd_find_altsetting(intf, value); - - /* set as current alternate setting */ - intf->curr_setting = setting; - - return RT_EOK; -} - -/** - * This function will set a configuration for an usb device. - * - * @param device the usb device object. - * @param wValue the configuration number. - * - * @return RT_EOK. - */ -rt_err_t rt_usbd_set_config(udevice_t device, rt_uint8_t value) -{ - uconfig_t cfg; - - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_set_config\n")); - - /* parameter check */ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(value <= device->dev_desc.bNumConfigurations); - - /* find a configuration */ - cfg = rt_usbd_find_config(device, value); - - /* set as current configuration */ - device->curr_cfg = cfg; - - dcd_set_config(device->dcd, value); - - return RT_TRUE; -} - -/** - * This function will bRequest an IO transaction. - * - * @param device the usb device object. - * @param ep the endpoint object. - * @param req IO bRequest. - * - * @return RT_EOK. - */ -rt_size_t rt_usbd_io_request(udevice_t device, uep_t ep, uio_request_t req) -{ - rt_size_t size = 0; - - RT_ASSERT(device != RT_NULL); - RT_ASSERT(req != RT_NULL); - - if(ep->stalled == RT_FALSE) - { - switch(req->req_type) - { - case UIO_REQUEST_READ_BEST: - case UIO_REQUEST_READ_FULL: - ep->request.remain_size = ep->request.size; - size = rt_usbd_ep_read_prepare(device, ep, req->buffer, req->size); - break; - case UIO_REQUEST_WRITE: - ep->request.remain_size = ep->request.size; - size = rt_usbd_ep_write(device, ep, req->buffer, req->size); - break; - default: - rt_kprintf("unknown request type\n"); - break; - } - } - else - { - rt_list_insert_before(&ep->request_list, &req->list); - RT_DEBUG_LOG(RT_DEBUG_USB, ("suspend a request\n")); - } - - return size; -} - -/** - * This function will set feature for an usb device. - * - * @param device the usb device object. - * @param wValue the configuration number. - * - * @return RT_EOK. - */ -rt_err_t rt_usbd_set_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index) -{ - RT_ASSERT(device != RT_NULL); - - if (value == USB_FEATURE_DEV_REMOTE_WAKEUP) - { - RT_DEBUG_LOG(RT_DEBUG_USB, ("set feature remote wakeup\n")); - } - else if (value == USB_FEATURE_ENDPOINT_HALT) - { - RT_DEBUG_LOG(RT_DEBUG_USB, ("set feature stall\n")); - dcd_ep_set_stall(device->dcd, (rt_uint32_t)(index & 0xFF)); - } - - return RT_EOK; -} - -/** - * This function will clear feature for an usb device. - * - * @param device the usb device object. - * @param wValue the configuration number. - * - * @return RT_EOK. - */ -rt_err_t rt_usbd_clear_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index) -{ - RT_ASSERT(device != RT_NULL); - - if (value == USB_FEATURE_DEV_REMOTE_WAKEUP) - { - RT_DEBUG_LOG(RT_DEBUG_USB, ("clear feature remote wakeup\n")); - } - else if (value == USB_FEATURE_ENDPOINT_HALT) - { - RT_DEBUG_LOG(RT_DEBUG_USB, ("clear feature stall\n")); - dcd_ep_clear_stall(device->dcd, (rt_uint32_t)(index & 0xFF)); - } - - return RT_EOK; -} - -rt_err_t rt_usbd_ep0_set_stall(udevice_t device) -{ - RT_ASSERT(device != RT_NULL); - - return dcd_ep_set_stall(device->dcd, 0); -} - -rt_err_t rt_usbd_ep0_clear_stall(udevice_t device) -{ - RT_ASSERT(device != RT_NULL); - - return dcd_ep_clear_stall(device->dcd, 0); -} - -rt_err_t rt_usbd_ep_set_stall(udevice_t device, uep_t ep) -{ - rt_err_t ret; - - RT_ASSERT(device != RT_NULL); - RT_ASSERT(ep != RT_NULL); - RT_ASSERT(ep->ep_desc != RT_NULL); - - ret = dcd_ep_set_stall(device->dcd, EP_ADDRESS(ep)); - if(ret == RT_EOK) - { - ep->stalled = RT_TRUE; - } - - return ret; -} - -rt_err_t rt_usbd_ep_clear_stall(udevice_t device, uep_t ep) -{ - rt_err_t ret; - - RT_ASSERT(device != RT_NULL); - RT_ASSERT(ep != RT_NULL); - RT_ASSERT(ep->ep_desc != RT_NULL); - - ret = dcd_ep_clear_stall(device->dcd, EP_ADDRESS(ep)); - if(ret == RT_EOK) - { - ep->stalled = RT_FALSE; - } - - return ret; -} - -static rt_err_t rt_usbd_ep_assign(udevice_t device, uep_t ep) -{ - int i = 0; - - RT_ASSERT(device != RT_NULL); - RT_ASSERT(device->dcd != RT_NULL); - RT_ASSERT(device->dcd->ep_pool != RT_NULL); - RT_ASSERT(ep != RT_NULL); - RT_ASSERT(ep->ep_desc != RT_NULL); - - while(device->dcd->ep_pool[i].addr != 0xFF) - { - if(device->dcd->ep_pool[i].status == ID_UNASSIGNED && - ep->ep_desc->bmAttributes == device->dcd->ep_pool[i].type && (EP_ADDRESS(ep) & 0x80) == device->dcd->ep_pool[i].dir) - { - EP_ADDRESS(ep) |= device->dcd->ep_pool[i].addr; - ep->id = &device->dcd->ep_pool[i]; - device->dcd->ep_pool[i].status = ID_ASSIGNED; - - RT_DEBUG_LOG(RT_DEBUG_USB, ("assigned %d\n", device->dcd->ep_pool[i].addr)); - return RT_EOK; - } - - i++; - } - - return -RT_ERROR; -} - -rt_err_t rt_usbd_ep_unassign(udevice_t device, uep_t ep) -{ - RT_ASSERT(device != RT_NULL); - RT_ASSERT(device->dcd != RT_NULL); - RT_ASSERT(device->dcd->ep_pool != RT_NULL); - RT_ASSERT(ep != RT_NULL); - RT_ASSERT(ep->ep_desc != RT_NULL); - - ep->id->status = ID_UNASSIGNED; - - return RT_EOK; -} - -rt_err_t rt_usbd_ep0_setup_handler(udcd_t dcd, struct urequest* setup) -{ - struct udev_msg msg; - rt_size_t size; - - RT_ASSERT(dcd != RT_NULL); - - if(setup == RT_NULL) - { - size = dcd_ep_read(dcd, EP0_OUT_ADDR, (void*)&msg.content.setup); - if(size != sizeof(struct urequest)) - { - rt_kprintf("read setup packet error\n"); - return -RT_ERROR; - } - } - else - { - rt_memcpy((void*)&msg.content.setup, (void*)setup, sizeof(struct urequest)); - } - - msg.type = USB_MSG_SETUP_NOTIFY; - msg.dcd = dcd; - rt_usbd_event_signal(&msg); - - return RT_EOK; -} - -rt_err_t rt_usbd_ep0_in_handler(udcd_t dcd) -{ - rt_int32_t remain, mps; - - RT_ASSERT(dcd != RT_NULL); - - if (dcd->stage != STAGE_DIN) - return RT_EOK; - - mps = dcd->ep0.id->maxpacket; - dcd->ep0.request.remain_size -= mps; - remain = dcd->ep0.request.remain_size; - - if (remain > 0) - { - if (remain >= mps) - { - remain = mps; - } - - dcd->ep0.request.buffer += mps; - dcd_ep_write(dcd, EP0_IN_ADDR, dcd->ep0.request.buffer, remain); - } - else - { - /* last packet is MPS multiple, so send ZLP packet */ - if ((remain == 0) && (dcd->ep0.request.size > 0)) - { - dcd->ep0.request.size = 0; - dcd_ep_write(dcd, EP0_IN_ADDR, RT_NULL, 0); - } - else - { - /* receive status */ - dcd->stage = STAGE_STATUS_OUT; - dcd_ep_read_prepare(dcd, EP0_OUT_ADDR, RT_NULL, 0); - } - } - - return RT_EOK; -} - -rt_err_t rt_usbd_ep0_out_handler(udcd_t dcd, rt_size_t size) -{ - struct udev_msg msg; - - RT_ASSERT(dcd != RT_NULL); - - msg.type = USB_MSG_EP0_OUT; - msg.dcd = dcd; - msg.content.ep_msg.size = size; - rt_usbd_event_signal(&msg); - - return RT_EOK; -} - -rt_err_t rt_usbd_ep_in_handler(udcd_t dcd, rt_uint8_t address, rt_size_t size) -{ - struct udev_msg msg; - - RT_ASSERT(dcd != RT_NULL); - - msg.type = USB_MSG_DATA_NOTIFY; - msg.dcd = dcd; - msg.content.ep_msg.ep_addr = address; - msg.content.ep_msg.size = size; - rt_usbd_event_signal(&msg); - - return RT_EOK; -} - -rt_err_t rt_usbd_ep_out_handler(udcd_t dcd, rt_uint8_t address, rt_size_t size) -{ - struct udev_msg msg; - - RT_ASSERT(dcd != RT_NULL); - - msg.type = USB_MSG_DATA_NOTIFY; - msg.dcd = dcd; - msg.content.ep_msg.ep_addr = address; - msg.content.ep_msg.size = size; - rt_usbd_event_signal(&msg); - - return RT_EOK; -} - -rt_err_t rt_usbd_reset_handler(udcd_t dcd) -{ - struct udev_msg msg; - - RT_ASSERT(dcd != RT_NULL); - - msg.type = USB_MSG_RESET; - msg.dcd = dcd; - rt_usbd_event_signal(&msg); - - return RT_EOK; -} - -rt_err_t rt_usbd_connect_handler(udcd_t dcd) -{ - struct udev_msg msg; - - RT_ASSERT(dcd != RT_NULL); - - msg.type = USB_MSG_PLUG_IN; - msg.dcd = dcd; - rt_usbd_event_signal(&msg); - - return RT_EOK; -} - -rt_err_t rt_usbd_disconnect_handler(udcd_t dcd) -{ - struct udev_msg msg; - - RT_ASSERT(dcd != RT_NULL); - - msg.type = USB_MSG_PLUG_OUT; - msg.dcd = dcd; - rt_usbd_event_signal(&msg); - - return RT_EOK; -} - -rt_err_t rt_usbd_sof_handler(udcd_t dcd) -{ - struct udev_msg msg; - - RT_ASSERT(dcd != RT_NULL); - - msg.type = USB_MSG_SOF; - msg.dcd = dcd; - rt_usbd_event_signal(&msg); - - return RT_EOK; -} - -rt_size_t rt_usbd_ep0_write(udevice_t device, void *buffer, rt_size_t size) -{ - uep_t ep0; - rt_size_t sent_size = 0; - - RT_ASSERT(device != RT_NULL); - RT_ASSERT(device->dcd != RT_NULL); - RT_ASSERT(buffer != RT_NULL); - RT_ASSERT(size > 0); - - ep0 = &device->dcd->ep0; - ep0->request.size = size; - ep0->request.buffer = (rt_uint8_t *)buffer; - ep0->request.remain_size = size; - if(size >= ep0->id->maxpacket) - { - sent_size = ep0->id->maxpacket; - } - else - { - sent_size = size; - } - device->dcd->stage = STAGE_DIN; - - return dcd_ep_write(device->dcd, EP0_IN_ADDR, ep0->request.buffer, sent_size); -} - -rt_size_t rt_usbd_ep0_read(udevice_t device, void *buffer, rt_size_t size, - rt_err_t (*rx_ind)(udevice_t device, rt_size_t size)) -{ - uep_t ep0; - rt_size_t read_size = 0; - - RT_ASSERT(device != RT_NULL); - RT_ASSERT(device->dcd != RT_NULL); - RT_ASSERT(buffer != RT_NULL); - - ep0 = &device->dcd->ep0; - ep0->request.buffer = (rt_uint8_t *)buffer; - ep0->request.remain_size = size; - ep0->rx_indicate = rx_ind; - if(size >= ep0->id->maxpacket) - { - read_size = ep0->id->maxpacket; - } - else - { - read_size = size; - } - device->dcd->stage = STAGE_DOUT; - dcd_ep_read_prepare(device->dcd, EP0_OUT_ADDR, buffer, read_size); - - return size; -} - -static struct rt_messagequeue usb_mq; - -/** - * This function is the main entry of usb device thread, it is in charge of - * processing all messages received from the usb message buffer. - * - * @param parameter the parameter of the usb device thread. - * - * @return none. - */ -static void rt_usbd_thread_entry(void* parameter) -{ - while(1) - { - struct udev_msg msg; - udevice_t device; - - /* receive message */ - if(rt_mq_recv(&usb_mq, &msg, sizeof(struct udev_msg), - RT_WAITING_FOREVER) != RT_EOK ) - continue; - - device = rt_usbd_find_device(msg.dcd); - if(device == RT_NULL) - { - rt_kprintf("invalid usb device\n"); - continue; - } - - RT_DEBUG_LOG(RT_DEBUG_USB, ("message type %d\n", msg.type)); - - switch (msg.type) - { - case USB_MSG_SOF: - _sof_notify(device); - break; - case USB_MSG_DATA_NOTIFY: - /* some buggy drivers will have USB_MSG_DATA_NOTIFY before the core - * got configured. */ - _data_notify(device, &msg.content.ep_msg); - break; - case USB_MSG_SETUP_NOTIFY: - _setup_request(device, &msg.content.setup); - break; - case USB_MSG_EP0_OUT: - _ep0_out_notify(device, &msg.content.ep_msg); - break; - case USB_MSG_RESET: - RT_DEBUG_LOG(RT_DEBUG_USB, ("reset %d\n", device->state)); - if (device->state == USB_STATE_ADDRESS || device->state == USB_STATE_CONFIGURED) - _stop_notify(device); - device->state = USB_STATE_NOTATTACHED; - break; - case USB_MSG_PLUG_IN: - device->state = USB_STATE_ATTACHED; - break; - case USB_MSG_PLUG_OUT: - device->state = USB_STATE_NOTATTACHED; - _stop_notify(device); - break; - default: - rt_kprintf("unknown msg type %d\n", msg.type); - break; - } - } -} - -/** - * This function will post an message to usb message queue, - * - * @param msg the message to be posted - * @param size the size of the message . - * - * @return the error code, RT_EOK on successfully. - */ -rt_err_t rt_usbd_event_signal(struct udev_msg* msg) -{ - RT_ASSERT(msg != RT_NULL); - - /* send message to usb message queue */ - return rt_mq_send(&usb_mq, (void*)msg, sizeof(struct udev_msg)); -} - - -ALIGN(RT_ALIGN_SIZE) -static rt_uint8_t usb_thread_stack[RT_USBD_THREAD_STACK_SZ]; -static struct rt_thread usb_thread; -#define USBD_MQ_MSG_SZ 32 -#define USBD_MQ_MAX_MSG 16 -/* internal of the message queue: every message is associated with a pointer, - * so in order to recveive USBD_MQ_MAX_MSG messages, we have to allocate more - * than USBD_MQ_MSG_SZ*USBD_MQ_MAX_MSG memory. */ -static rt_uint8_t usb_mq_pool[(USBD_MQ_MSG_SZ+sizeof(void*))*USBD_MQ_MAX_MSG]; - -/** - * This function will initialize usb device thread. - * - * @return none. - * - */ -rt_err_t rt_usbd_core_init(void) -{ - rt_list_init(&device_list); - - /* create an usb message queue */ - rt_mq_init(&usb_mq, - "usbd", - usb_mq_pool, USBD_MQ_MSG_SZ, - sizeof(usb_mq_pool), - RT_IPC_FLAG_FIFO); - - /* init usb device thread */ - rt_thread_init(&usb_thread, - "usbd", - rt_usbd_thread_entry, RT_NULL, - usb_thread_stack, RT_USBD_THREAD_STACK_SZ, - RT_USBD_THREAD_PRIO, 20); - /* rt_thread_init should always be OK, so start the thread without further - * checking. */ - return rt_thread_startup(&usb_thread); -} - diff --git a/components/drivers/usb/usbdevice/core/usbdevice_core.c b/components/drivers/usb/usbdevice/core/usbdevice_core.c new file mode 100644 index 0000000000..ef569d7bf2 --- /dev/null +++ b/components/drivers/usb/usbdevice/core/usbdevice_core.c @@ -0,0 +1,2237 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2012-10-01 Yi Qiu first version + * 2012-12-12 heyuanjie87 change endpoint and function handler + * 2012-12-30 heyuanjie87 change inferface handler + * 2013-04-26 aozima add DEVICEQUALIFIER support. + * 2013-07-25 Yi Qiu update for USB CV test + * 2017-11-15 ZYH fix ep0 transform error + */ + +#include +#include "drivers/usb_common.h" +#include "drivers/usb_device.h" + +static rt_list_t device_list; + +static rt_size_t rt_usbd_ep_write(udevice_t device, uep_t ep, void *buffer, rt_size_t size); +static rt_size_t rt_usbd_ep_read_prepare(udevice_t device, uep_t ep, void *buffer, rt_size_t size); +static rt_err_t rt_usbd_ep_assign(udevice_t device, uep_t ep); +rt_err_t rt_usbd_ep_unassign(udevice_t device, uep_t ep); + +/** + * This function will handle get_device_descriptor bRequest. + * + * @param device the usb device object. + * @param setup the setup bRequest. + * + * @return RT_EOK on successful. + */ +static rt_err_t _get_device_descriptor(struct udevice* device, ureq_t setup) +{ + rt_size_t size; + + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(setup != RT_NULL); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("_get_device_descriptor\n")); + + /* device descriptor wLength should less than USB_DESC_LENGTH_DEVICE*/ + size = (setup->wLength > USB_DESC_LENGTH_DEVICE) ? + USB_DESC_LENGTH_DEVICE : setup->wLength; + + /* send device descriptor to endpoint 0 */ + rt_usbd_ep0_write(device, (rt_uint8_t*) &device->dev_desc, size); + + return RT_EOK; +} + +/** + * This function will handle get_config_descriptor bRequest. + * + * @param device the usb device object. + * @param setup the setup bRequest. + * + * @return RT_EOK on successful. + */ +static rt_err_t _get_config_descriptor(struct udevice* device, ureq_t setup) +{ + rt_size_t size; + ucfg_desc_t cfg_desc; + + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(setup != RT_NULL); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("_get_config_descriptor\n")); + + cfg_desc = &device->curr_cfg->cfg_desc; + size = (setup->wLength > cfg_desc->wTotalLength) ? + cfg_desc->wTotalLength : setup->wLength; + + /* send configuration descriptor to endpoint 0 */ + rt_usbd_ep0_write(device, (rt_uint8_t*)cfg_desc, size); + + return RT_EOK; +} + +/** + * This function will handle get_string_descriptor bRequest. + * + * @param device the usb device object. + * @param setup the setup bRequest. + * + * @return RT_EOK on successful, -RT_ERROR on invalid bRequest. + */ +static rt_err_t _get_string_descriptor(struct udevice* device, ureq_t setup) +{ + struct ustring_descriptor str_desc; + rt_uint8_t index, i; + rt_uint32_t len; + + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(setup != RT_NULL); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("_get_string_descriptor\n")); + + str_desc.type = USB_DESC_TYPE_STRING; + index = setup->wValue & 0xFF; + + if(index == 0xEE) + { + index = USB_STRING_OS_INDEX; + } + + if(index > USB_STRING_MAX) + { + rt_kprintf("unknown string index\n"); + rt_usbd_ep0_set_stall(device); + return -RT_ERROR; + } + else if(index == USB_STRING_LANGID_INDEX) + { + str_desc.bLength = 4; + str_desc.String[0] = 0x09; + str_desc.String[1] = 0x04; + } + else + { + len = rt_strlen(device->str[index]); + str_desc.bLength = len*2 + 2; + + for(i=0; istr[index][i]; + str_desc.String[i*2 + 1] = 0; + } + } + + if (setup->wLength > str_desc.bLength) + len = str_desc.bLength; + else + len = setup->wLength; + + /* send string descriptor to endpoint 0 */ + rt_usbd_ep0_write(device, (rt_uint8_t*)&str_desc, len); + + return RT_EOK; +} + +static rt_err_t _get_qualifier_descriptor(struct udevice* device, ureq_t setup) +{ + RT_DEBUG_LOG(RT_DEBUG_USB, ("_get_qualifier_descriptor\n")); + + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(setup != RT_NULL); + + if(device->dev_qualifier && device->dcd->device_is_hs) + { + /* send device qualifier descriptor to endpoint 0 */ + rt_usbd_ep0_write(device, (rt_uint8_t*)device->dev_qualifier, + sizeof(struct usb_qualifier_descriptor)); + } + else + { + rt_usbd_ep0_set_stall(device); + } + + return RT_EOK; +} + +/** + * This function will handle get_descriptor bRequest. + * + * @param device the usb device object. + * @param setup the setup bRequest. + * + * @return RT_EOK on successful. + */ +static rt_err_t _get_descriptor(struct udevice* device, ureq_t setup) +{ + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(setup != RT_NULL); + + if(setup->request_type == USB_REQ_TYPE_DIR_IN) + { + switch(setup->wValue >> 8) + { + case USB_DESC_TYPE_DEVICE: + _get_device_descriptor(device, setup); + break; + case USB_DESC_TYPE_CONFIGURATION: + _get_config_descriptor(device, setup); + break; + case USB_DESC_TYPE_STRING: + _get_string_descriptor(device, setup); + break; + case USB_DESC_TYPE_DEVICEQUALIFIER: + /* If a full-speed only device (with a device descriptor version number equal to 0200H) receives a + GetDescriptor() request for a device_qualifier, it must respond with a request error. The host must not make + a request for an other_speed_configuration descriptor unless it first successfully retrieves the + device_qualifier descriptor. */ + if(device->dcd->device_is_hs) + { + _get_qualifier_descriptor(device, setup); + } + else + { + rt_usbd_ep0_set_stall(device); + } + break; + case USB_DESC_TYPE_OTHERSPEED: + _get_config_descriptor(device, setup); + break; + default: + rt_kprintf("unsupported descriptor request\n"); + rt_usbd_ep0_set_stall(device); + break; + } + } + else + { + rt_kprintf("request direction error\n"); + rt_usbd_ep0_set_stall(device); + } + + return RT_EOK; +} + +/** + * This function will handle get_interface bRequest. + * + * @param device the usb device object. + * @param setup the setup bRequest. + * + * @return RT_EOK on successful. + */ +static rt_err_t _get_interface(struct udevice* device, ureq_t setup) +{ + rt_uint8_t value; + uintf_t intf; + ufunction_t func; + + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(setup != RT_NULL); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("_get_interface\n")); + + if (device->state != USB_STATE_CONFIGURED) + { + rt_usbd_ep0_set_stall(device); + return -RT_ERROR; + } + + /* find the specified interface and its alternate setting */ + intf = rt_usbd_find_interface(device, setup->wIndex & 0xFF, &func); + value = intf->curr_setting->intf_desc->bAlternateSetting; + + /* send the interface alternate setting to endpoint 0*/ + rt_usbd_ep0_write(device, &value, 1); + + if (intf->handler) + { + intf->handler(func, setup); + } + + return RT_EOK; +} + +/** + * This function will handle set_interface bRequest. + * + * @param device the usb device object. + * @param setup the setup bRequest. + * + * @return RT_EOK on successful. + */ +static rt_err_t _set_interface(struct udevice* device, ureq_t setup) +{ + ufunction_t func; + uintf_t intf; + uep_t ep; + struct rt_list_node* i; + ualtsetting_t setting; + + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(setup != RT_NULL); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("_set_interface\n")); + + if (device->state != USB_STATE_CONFIGURED) + { + rt_usbd_ep0_set_stall(device); + return -RT_ERROR; + } + + /* find the specified interface */ + intf = rt_usbd_find_interface(device, setup->wIndex & 0xFF, &func); + + /* set alternate setting to the interface */ + rt_usbd_set_altsetting(intf, setup->wValue & 0xFF); + setting = intf->curr_setting; + + /* start all endpoints of the interface alternate setting */ + for(i=setting->ep_list.next; i != &setting->ep_list; i=i->next) + { + ep = (uep_t)rt_list_entry(i, struct uendpoint, list); + dcd_ep_disable(device->dcd, ep); + dcd_ep_enable(device->dcd, ep); + } + dcd_ep0_send_status(device->dcd); + + if (intf->handler) + { + intf->handler(func, setup); + } + + return RT_EOK; +} + +/** + * This function will handle get_config bRequest. + * + * @param device the usb device object. + * @param setup the setup bRequest. + * + * @return RT_EOK on successful. + */ +static rt_err_t _get_config(struct udevice* device, ureq_t setup) +{ + rt_uint8_t value; + + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(setup != RT_NULL); + RT_ASSERT(device->curr_cfg != RT_NULL); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("_get_config\n")); + + if (device->state == USB_STATE_CONFIGURED) + { + /* get current configuration */ + value = device->curr_cfg->cfg_desc.bConfigurationValue; + } + else + { + value = 0; + } + /* write the current configuration to endpoint 0 */ + rt_usbd_ep0_write(device, &value, 1); + + return RT_EOK; +} + +/** + * This function will handle set_config bRequest. + * + * @param device the usb device object. + * @param setup the setup bRequest. + * + * @return RT_EOK on successful. + */ +static rt_err_t _set_config(struct udevice* device, ureq_t setup) +{ + struct rt_list_node *i, *j, *k; + uconfig_t cfg; + uintf_t intf; + ualtsetting_t setting; + uep_t ep; + + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(setup != RT_NULL); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("_set_config\n")); + + if (setup->wValue > device->dev_desc.bNumConfigurations) + { + rt_usbd_ep0_set_stall(device); + return -RT_ERROR; + } + + if (setup->wValue == 0) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("address state\n")); + device->state = USB_STATE_ADDRESS; + + goto _exit; + } + + /* set current configuration */ + rt_usbd_set_config(device, setup->wValue); + cfg = device->curr_cfg; + + for (i=cfg->func_list.next; i!=&cfg->func_list; i=i->next) + { + /* run all functiones and their endpoints in the configuration */ + ufunction_t func = (ufunction_t)rt_list_entry(i, struct ufunction, list); + for(j=func->intf_list.next; j!=&func->intf_list; j=j->next) + { + intf = (uintf_t)rt_list_entry(j, struct uinterface, list); + setting = intf->curr_setting; + for(k=setting->ep_list.next; k != &setting->ep_list; k=k->next) + { + ep = (uep_t)rt_list_entry(k, struct uendpoint, list); + + /* first disable then enable an endpoint */ + dcd_ep_disable(device->dcd, ep); + dcd_ep_enable(device->dcd, ep); + } + } + /* after enabled endpoints, then enable function */ + FUNC_ENABLE(func); + } + + device->state = USB_STATE_CONFIGURED; + +_exit: + /* issue status stage */ + dcd_ep0_send_status(device->dcd); + + return RT_EOK; +} + +/** + * This function will handle set_address bRequest. + * + * @param device the usb device object. + * @param setup the setup bRequest. + * + * @return RT_EOK on successful. + */ +static rt_err_t _set_address(struct udevice* device, ureq_t setup) +{ + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(setup != RT_NULL); + + /* set address in device control driver */ + dcd_set_address(device->dcd, setup->wValue); + + /* issue status stage */ + dcd_ep0_send_status(device->dcd); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("_set_address\n")); + + device->state = USB_STATE_ADDRESS; + + return RT_EOK; +} + +/** + * This function will handle standard bRequest to + * interface that defined in function-specifics + * + * @param device the usb device object. + * @param setup the setup bRequest. + * + * @return RT_EOK on successful. + */ +static rt_err_t _request_interface(struct udevice* device, ureq_t setup) +{ + uintf_t intf; + ufunction_t func; + rt_err_t ret; + + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(setup != RT_NULL); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("_request_interface\n")); + + intf = rt_usbd_find_interface(device, setup->wIndex & 0xFF, &func); + if (intf != RT_NULL) + { + ret = intf->handler(func, setup); + } + else + { + ret = -RT_ERROR; + } + + return ret; +} + +/** + * This function will handle standard bRequest. + * + * @param device the usb device object. + * @param setup the setup bRequest. + * + * @return RT_EOK on successful. + */ +static rt_err_t _standard_request(struct udevice* device, ureq_t setup) +{ + udcd_t dcd; + rt_uint16_t value = 0; + + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(setup != RT_NULL); + + dcd = device->dcd; + + switch(setup->request_type & USB_REQ_TYPE_RECIPIENT_MASK) + { + case USB_REQ_TYPE_DEVICE: + switch(setup->bRequest) + { + case USB_REQ_GET_STATUS: + rt_usbd_ep0_write(device, &value, 2); + break; + case USB_REQ_CLEAR_FEATURE: + rt_usbd_clear_feature(device, setup->wValue, setup->wIndex); + dcd_ep0_send_status(dcd); + break; + case USB_REQ_SET_FEATURE: + rt_usbd_set_feature(device, setup->wValue, setup->wIndex); + break; + case USB_REQ_SET_ADDRESS: + _set_address(device, setup); + break; + case USB_REQ_GET_DESCRIPTOR: + _get_descriptor(device, setup); + break; + case USB_REQ_SET_DESCRIPTOR: + rt_usbd_ep0_set_stall(device); + break; + case USB_REQ_GET_CONFIGURATION: + _get_config(device, setup); + break; + case USB_REQ_SET_CONFIGURATION: + _set_config(device, setup); + break; + default: + rt_kprintf("unknown device request\n"); + rt_usbd_ep0_set_stall(device); + break; + } + break; + case USB_REQ_TYPE_INTERFACE: + switch(setup->bRequest) + { + case USB_REQ_GET_INTERFACE: + _get_interface(device, setup); + break; + case USB_REQ_SET_INTERFACE: + _set_interface(device, setup); + break; + default: + if (_request_interface(device, setup) != RT_EOK) + { + rt_kprintf("unknown interface request\n"); + rt_usbd_ep0_set_stall(device); + return - RT_ERROR; + } + else + break; + } + break; + case USB_REQ_TYPE_ENDPOINT: + switch(setup->bRequest) + { + case USB_REQ_GET_STATUS: + { + uep_t ep; + + ep = rt_usbd_find_endpoint(device, RT_NULL, setup->wIndex); + value = ep->stalled; + rt_usbd_ep0_write(device, &value, 2); + } + break; + case USB_REQ_CLEAR_FEATURE: + { + uep_t ep; + uio_request_t req; + struct rt_list_node *node; + + ep = rt_usbd_find_endpoint(device, RT_NULL, setup->wIndex); + if(USB_EP_HALT == setup->wValue && ep->stalled == RT_TRUE) + { + rt_usbd_clear_feature(device, setup->wValue, setup->wIndex); + dcd_ep0_send_status(dcd); + ep->stalled = RT_FALSE; + + for (node = ep->request_list.next; node != &ep->request_list; node = node->next) + { + req = (uio_request_t)rt_list_entry(node, struct uio_request, list); + rt_usbd_io_request(device, ep, req); + RT_DEBUG_LOG(RT_DEBUG_USB, ("fired a request\n")); + } + + rt_list_init(&ep->request_list); + } + } + break; + case USB_REQ_SET_FEATURE: + { + uep_t ep; + + if(USB_EP_HALT == setup->wValue) + { + ep = rt_usbd_find_endpoint(device, RT_NULL, setup->wIndex); + ep->stalled = RT_TRUE; + rt_usbd_set_feature(device, setup->wValue, setup->wIndex); + dcd_ep0_send_status(dcd); + } + } + break; + case USB_REQ_SYNCH_FRAME: + break; + default: + rt_kprintf("unknown endpoint request\n"); + rt_usbd_ep0_set_stall(device); + break; + } + break; + case USB_REQ_TYPE_OTHER: + rt_kprintf("unknown other type request\n"); + rt_usbd_ep0_set_stall(device); + break; + default: + rt_kprintf("unknown type request\n"); + rt_usbd_ep0_set_stall(device); + break; + } + + return RT_EOK; +} + +/** + * This function will handle function bRequest. + * + * @param device the usb device object. + * @param setup the setup bRequest. + * + * @return RT_EOK on successful, -RT_ERROR on invalid bRequest. + */ +static rt_err_t _function_request(udevice_t device, ureq_t setup) +{ + uintf_t intf; + ufunction_t func; + + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(setup != RT_NULL); + + /* verify bRequest wValue */ + if(setup->wIndex > device->curr_cfg->cfg_desc.bNumInterfaces) + { + rt_usbd_ep0_set_stall(device); + return -RT_ERROR; + } + + switch(setup->request_type & USB_REQ_TYPE_RECIPIENT_MASK) + { + case USB_REQ_TYPE_INTERFACE: + intf = rt_usbd_find_interface(device, setup->wIndex & 0xFF, &func); + if(intf == RT_NULL) + { + rt_kprintf("unkwown interface request\n"); + rt_usbd_ep0_set_stall(device); + } + else + { + intf->handler(func, setup); + } + break; + case USB_REQ_TYPE_ENDPOINT: + break; + default: + rt_kprintf("unknown function request type\n"); + rt_usbd_ep0_set_stall(device); + break; + } + + return RT_EOK; +} +static rt_err_t _vendor_request(udevice_t device, ureq_t setup) +{ + static rt_uint8_t * usb_comp_id_desc = RT_NULL; + static rt_uint32_t usb_comp_id_desc_size = 0; + usb_os_func_comp_id_desc_t func_comp_id_desc; + uintf_t intf; + ufunction_t func; + switch(setup->bRequest) + { + case 'A': + switch(setup->wIndex) + { + case 0x04: + if(rt_list_len(&device->os_comp_id_desc->func_desc) == 0) + { + rt_usbd_ep0_set_stall(device); + return RT_EOK; + } + if(usb_comp_id_desc == RT_NULL) + { + rt_uint8_t * pusb_comp_id_desc; + rt_list_t *p; + usb_comp_id_desc_size = sizeof(struct usb_os_header_comp_id_descriptor) + + (sizeof(struct usb_os_function_comp_id_descriptor)-sizeof(rt_list_t))*rt_list_len(&device->os_comp_id_desc->func_desc); + + usb_comp_id_desc = (rt_uint8_t *)rt_malloc(usb_comp_id_desc_size); + RT_ASSERT(usb_comp_id_desc != RT_NULL); + device->os_comp_id_desc->head_desc.dwLength = usb_comp_id_desc_size; + pusb_comp_id_desc = usb_comp_id_desc; + rt_memcpy((void *)pusb_comp_id_desc,(void *)&device->os_comp_id_desc->head_desc,sizeof(struct usb_os_header_comp_id_descriptor)); + pusb_comp_id_desc += sizeof(struct usb_os_header_comp_id_descriptor); + + for (p = device->os_comp_id_desc->func_desc.next; p != &device->os_comp_id_desc->func_desc; p = p->next) + { + func_comp_id_desc = rt_list_entry(p,struct usb_os_function_comp_id_descriptor,list); + rt_memcpy(pusb_comp_id_desc,(void *)&func_comp_id_desc->bFirstInterfaceNumber, + sizeof(struct usb_os_function_comp_id_descriptor)-sizeof(rt_list_t)); + pusb_comp_id_desc += sizeof(struct usb_os_function_comp_id_descriptor)-sizeof(rt_list_t); + } + } + rt_usbd_ep0_write(device, (void*)usb_comp_id_desc, setup->wLength); + break; + case 0x05: + intf = rt_usbd_find_interface(device, setup->wValue & 0xFF, &func); + if(intf != RT_NULL) + { + intf->handler(func, setup); + } + break; + } + + break; + } + return RT_EOK; +} +static rt_err_t _dump_setup_packet(ureq_t setup) +{ + RT_DEBUG_LOG(RT_DEBUG_USB, ("[\n")); + RT_DEBUG_LOG(RT_DEBUG_USB, (" setup_request : 0x%x\n", + setup->request_type)); + RT_DEBUG_LOG(RT_DEBUG_USB, (" value : 0x%x\n", setup->wValue)); + RT_DEBUG_LOG(RT_DEBUG_USB, (" length : 0x%x\n", setup->wLength)); + RT_DEBUG_LOG(RT_DEBUG_USB, (" index : 0x%x\n", setup->wIndex)); + RT_DEBUG_LOG(RT_DEBUG_USB, (" request : 0x%x\n", setup->bRequest)); + RT_DEBUG_LOG(RT_DEBUG_USB, ("]\n")); + + return RT_EOK; +} + +/** + * This function will handle setup bRequest. + * + * @param device the usb device object. + * @param setup the setup bRequest. + * + * @return RT_EOK on successful, -RT_ERROR on invalid bRequest. + */ +static rt_err_t _setup_request(udevice_t device, ureq_t setup) +{ + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(setup != RT_NULL); + + _dump_setup_packet(setup); + + switch((setup->request_type & USB_REQ_TYPE_MASK)) + { + case USB_REQ_TYPE_STANDARD: + _standard_request(device, setup); + break; + case USB_REQ_TYPE_CLASS: + _function_request(device, setup); + break; + case USB_REQ_TYPE_VENDOR: + _vendor_request(device, setup); + break; + default: + rt_kprintf("unknown setup request type\n"); + rt_usbd_ep0_set_stall(device); + return -RT_ERROR; + } + + return RT_EOK; +} + +/** + * This function will hanle data notify event. + * + * @param device the usb device object. + * @param ep_msg the endpoint message. + * + * @return RT_EOK. + */ +static rt_err_t _data_notify(udevice_t device, struct ep_msg* ep_msg) +{ + uep_t ep; + ufunction_t func; + rt_size_t size = 0; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(ep_msg != RT_NULL); + + if (device->state != USB_STATE_CONFIGURED) + { + return -RT_ERROR; + } + + ep = rt_usbd_find_endpoint(device, &func, ep_msg->ep_addr); + if(ep == RT_NULL) + { + rt_kprintf("invalid endpoint\n"); + return -RT_ERROR; + } + + if(EP_ADDRESS(ep) & USB_DIR_IN) + { + size = ep_msg->size; + if(ep->request.remain_size >= EP_MAXPACKET(ep)) + { + dcd_ep_write(device->dcd, EP_ADDRESS(ep), ep->request.buffer, EP_MAXPACKET(ep)); + ep->request.remain_size -= EP_MAXPACKET(ep); + ep->request.buffer += EP_MAXPACKET(ep); + } + else if(ep->request.remain_size > 0) + { + dcd_ep_write(device->dcd, EP_ADDRESS(ep), ep->request.buffer, ep->request.remain_size); + ep->request.remain_size = 0; + } + else + { + EP_HANDLER(ep, func, size); + } + } + else + { + size = ep_msg->size; + if(ep->request.remain_size == 0) + { + return RT_EOK; + } + + if(size == 0) + { + size = dcd_ep_read(device->dcd, EP_ADDRESS(ep), ep->request.buffer); + } + ep->request.remain_size -= size; + ep->request.buffer += size; + + if(ep->request.req_type == UIO_REQUEST_READ_BEST) + { + EP_HANDLER(ep, func, size); + } + else if(ep->request.remain_size == 0) + { + EP_HANDLER(ep, func, ep->request.size); + } + else + { + dcd_ep_read_prepare(device->dcd, EP_ADDRESS(ep), ep->request.buffer, ep->request.remain_size > EP_MAXPACKET(ep) ? EP_MAXPACKET(ep) : ep->request.remain_size); + } + } + + return RT_EOK; +} + +static rt_err_t _ep0_out_notify(udevice_t device, struct ep_msg* ep_msg) +{ + uep_t ep0; + rt_size_t size; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(ep_msg != RT_NULL); + RT_ASSERT(device->dcd != RT_NULL); + + ep0 = &device->dcd->ep0; + size = ep_msg->size; + + if(ep0->request.remain_size == 0) + { + return RT_EOK; + } + if(size == 0) + { + size = dcd_ep_read(device->dcd, EP0_OUT_ADDR, ep0->request.buffer); + if(size == 0) + { + return RT_EOK; + } + } + + ep0->request.remain_size -= size; + ep0->request.buffer += size; + if(ep0->request.remain_size == 0) + { + /* invoke callback */ + if(ep0->rx_indicate != RT_NULL) + { + ep0->rx_indicate(device, size); + } + } + else + { + rt_usbd_ep0_read(device, ep0->request.buffer, ep0->request.remain_size,ep0->rx_indicate); + } + + return RT_EOK; +} + +/** + * This function will notity sof event to all of function. + * + * @param device the usb device object. + * + * @return RT_EOK. + */ +static rt_err_t _sof_notify(udevice_t device) +{ + struct rt_list_node *i; + ufunction_t func; + + RT_ASSERT(device != RT_NULL); + + /* to notity every function that sof event comes */ + for (i=device->curr_cfg->func_list.next; + i!=&device->curr_cfg->func_list; i=i->next) + { + func = (ufunction_t)rt_list_entry(i, struct ufunction, list); + if(func->ops->sof_handler != RT_NULL) + func->ops->sof_handler(func); + } + + return RT_EOK; +} + +/** + * This function will disable all USB functions. + * + * @param device the usb device object. + * + * @return RT_EOK. + */ +static rt_err_t _stop_notify(udevice_t device) +{ + struct rt_list_node *i; + ufunction_t func; + + RT_ASSERT(device != RT_NULL); + + /* to notity every function */ + for (i = device->curr_cfg->func_list.next; + i != &device->curr_cfg->func_list; + i = i->next) + { + func = (ufunction_t)rt_list_entry(i, struct ufunction, list); + FUNC_DISABLE(func); + } + + return RT_EOK; +} + +static rt_size_t rt_usbd_ep_write(udevice_t device, uep_t ep, void *buffer, rt_size_t size) +{ + rt_uint16_t maxpacket; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(device->dcd != RT_NULL); + RT_ASSERT(ep != RT_NULL); + + rt_enter_critical(); + maxpacket = EP_MAXPACKET(ep); + if(ep->request.remain_size >= maxpacket) + { + dcd_ep_write(device->dcd, EP_ADDRESS(ep), ep->request.buffer, maxpacket); + ep->request.remain_size -= maxpacket; + ep->request.buffer += maxpacket; + } + else + { + dcd_ep_write(device->dcd, EP_ADDRESS(ep), ep->request.buffer, + ep->request.remain_size); + ep->request.remain_size = 0; + } + rt_exit_critical(); + return size; +} + +static rt_size_t rt_usbd_ep_read_prepare(udevice_t device, uep_t ep, void *buffer, rt_size_t size) +{ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(device->dcd != RT_NULL); + RT_ASSERT(ep != RT_NULL); + RT_ASSERT(buffer != RT_NULL); + RT_ASSERT(ep->ep_desc != RT_NULL); + + return dcd_ep_read_prepare(device->dcd, EP_ADDRESS(ep), buffer, size > EP_MAXPACKET(ep) ? EP_MAXPACKET(ep) : size); +} + +/** + * This function will create an usb device object. + * + * @param ustring the usb string array to contain string descriptor. + * + * @return an usb device object on success, RT_NULL on fail. + */ +udevice_t rt_usbd_device_new(void) +{ + udevice_t udevice; + + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_device_new\n")); + + /* allocate memory for the object */ + udevice = (udevice_t)rt_malloc(sizeof(struct udevice)); + if(udevice == RT_NULL) + { + rt_kprintf("alloc memory failed\n"); + return RT_NULL; + } + rt_memset(udevice, 0, sizeof(struct udevice)); + + /* to initialize configuration list */ + rt_list_init(&udevice->cfg_list); + + /* insert the device object to device list */ + rt_list_insert_before(&device_list, &udevice->list); + + return udevice; +} + +/** + * This function will set usb device string description. + * + * @param device the usb device object. + * @param ustring pointer to string pointer array. + * + * @return RT_EOK. + */ +rt_err_t rt_usbd_device_set_string(udevice_t device, const char** ustring) +{ + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(ustring != RT_NULL); + + /* set string descriptor array to the device object */ + device->str = ustring; + + return RT_EOK; +} + +rt_err_t rt_usbd_device_set_os_comp_id_desc(udevice_t device, usb_os_comp_id_desc_t os_comp_id_desc) +{ + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(os_comp_id_desc != RT_NULL); + + /* set string descriptor array to the device object */ + device->os_comp_id_desc = os_comp_id_desc; + rt_list_init(&device->os_comp_id_desc->func_desc); + return RT_EOK; +} + +rt_err_t rt_usbd_device_set_qualifier(udevice_t device, struct usb_qualifier_descriptor* qualifier) +{ + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(qualifier != RT_NULL); + + device->dev_qualifier = qualifier; + + return RT_EOK; +} + +/** + * This function will set an usb controller driver to a device. + * + * @param device the usb device object. + * @param dcd the usb device controller driver. + * + * @return RT_EOK on successful. + */ +rt_err_t rt_usbd_device_set_controller(udevice_t device, udcd_t dcd) +{ + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(dcd != RT_NULL); + + /* set usb device controller driver to the device */ + device->dcd = dcd; + + return RT_EOK; +} + +/** + * This function will set an usb device descriptor to a device. + * + * @param device the usb device object. + * @param dev_desc the usb device descriptor. + * + * @return RT_EOK on successful. + */ +rt_err_t rt_usbd_device_set_descriptor(udevice_t device, udev_desc_t dev_desc) +{ + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(dev_desc != RT_NULL); + + /* copy the usb device descriptor to the device */ + rt_memcpy((void *)&device->dev_desc, (void *)dev_desc, USB_DESC_LENGTH_DEVICE); + + return RT_EOK; +} + +/** + * This function will create an usb configuration object. + * + * @param none. + * + * @return an usb configuration object. + */ +uconfig_t rt_usbd_config_new(void) +{ + uconfig_t cfg; + + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_config_new\n")); + + /* allocate memory for the object */ + cfg = (uconfig_t)rt_malloc(sizeof(struct uconfig)); + if(cfg == RT_NULL) + { + rt_kprintf("alloc memory failed\n"); + return RT_NULL; + } + rt_memset(cfg, 0, sizeof(struct uconfig)); + + /* set default wValue */ + cfg->cfg_desc.bLength = USB_DESC_LENGTH_CONFIG; + cfg->cfg_desc.type = USB_DESC_TYPE_CONFIGURATION; + cfg->cfg_desc.wTotalLength = USB_DESC_LENGTH_CONFIG; + cfg->cfg_desc.bmAttributes = 0xC0; + cfg->cfg_desc.MaxPower = 0x32; + + /* to initialize function object list */ + rt_list_init(&cfg->func_list); + + return cfg; +} + +/** + * This function will create an usb interface object. + * + * @param device the usb device object. + * @handler the callback handler of object + * + * @return an usb interface object on success, RT_NULL on fail. + */ +uintf_t rt_usbd_interface_new(udevice_t device, uintf_handler_t handler) +{ + uintf_t intf; + + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_interface_new\n")); + + /* parameter check */ + RT_ASSERT(device != RT_NULL); + + /* allocate memory for the object */ + intf = (uintf_t)rt_malloc(sizeof(struct uinterface)); + if(intf == RT_NULL) + { + rt_kprintf("alloc memory failed\n"); + return RT_NULL; + } + intf->intf_num = device->nr_intf; + device->nr_intf++; + intf->handler = handler; + intf->curr_setting = RT_NULL; + + /* to initialize the alternate setting object list */ + rt_list_init(&intf->setting_list); + + return intf; +} + +/** + * This function will create an usb alternate setting object. + * + * @param intf_desc the interface descriptor. + * @desc_size the size of the interface descriptor. + * + * @return an usb alternate setting object on success, RT_NULL on fail. + */ +ualtsetting_t rt_usbd_altsetting_new(rt_size_t desc_size) +{ + ualtsetting_t setting; + + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_altsetting_new\n")); + + /* parameter check */ + RT_ASSERT(desc_size > 0); + + /* allocate memory for the object */ + setting = (ualtsetting_t)rt_malloc(sizeof(struct ualtsetting)); + if(setting == RT_NULL) + { + rt_kprintf("alloc memory failed\n"); + return RT_NULL; + } + /* allocate memory for the desc */ + setting->desc = rt_malloc(desc_size); + if (setting->desc == RT_NULL) + { + rt_kprintf("alloc desc memory failed\n"); + rt_free(setting); + return RT_NULL; + } + + setting->desc_size = desc_size; + setting->intf_desc = RT_NULL; + + /* to initialize endpoint list */ + rt_list_init(&setting->ep_list); + + return setting; +} + +/** + * This function will config an desc in alternate setting object. + * + * @param setting the altsetting to be config. + * @param desc use it to init desc in setting. + * @param intf_pos the offset of interface descriptor in desc. + * + * @return RT_EOK. + */ +rt_err_t rt_usbd_altsetting_config_descriptor(ualtsetting_t setting, const void* desc, rt_off_t intf_pos) +{ + RT_ASSERT(setting != RT_NULL); + RT_ASSERT(setting->desc !=RT_NULL); + + rt_memcpy(setting->desc, desc, setting->desc_size); + setting->intf_desc = (uintf_desc_t)((char*)setting->desc + intf_pos); + + return RT_EOK; +} + +/** + * This function will create an usb function object. + * + * @param device the usb device object. + * @param dev_desc the device descriptor. + * @param ops the operation set. + * + * @return an usb function object on success, RT_NULL on fail. + */ +ufunction_t rt_usbd_function_new(udevice_t device, udev_desc_t dev_desc, + ufunction_ops_t ops) +{ + ufunction_t func; + + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_function_new\n")); + + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(dev_desc != RT_NULL); + + /* allocate memory for the object */ + func = (ufunction_t)rt_malloc(sizeof(struct ufunction)); + if(func == RT_NULL) + { + rt_kprintf("alloc memory failed\n"); + return RT_NULL; + } + func->dev_desc = dev_desc; + func->ops = ops; + func->device = device; + func->enabled = RT_FALSE; + + /* to initialize interface list */ + rt_list_init(&func->intf_list); + + return func; +} + +/** + * This function will create an usb endpoint object. + * + * @param ep_desc the endpoint descriptor. + * @handler the callback handler of object + * + * @return an usb endpoint object on success, RT_NULL on fail. + */ +uep_t rt_usbd_endpoint_new(uep_desc_t ep_desc, udep_handler_t handler) +{ + uep_t ep; + + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_endpoint_new\n")); + + /* parameter check */ + RT_ASSERT(ep_desc != RT_NULL); + + /* allocate memory for the object */ + ep = (uep_t)rt_malloc(sizeof(struct uendpoint)); + if(ep == RT_NULL) + { + rt_kprintf("alloc memory failed\n"); + return RT_NULL; + } + ep->ep_desc = ep_desc; + ep->handler = handler; + ep->buffer = RT_NULL; + ep->stalled = RT_FALSE; + rt_list_init(&ep->request_list); + + return ep; +} + +/** + * This function will find an usb device object. + * + * @dcd usd device controller driver. + * + * @return an usb device object on found or RT_NULL on not found. + */ +udevice_t rt_usbd_find_device(udcd_t dcd) +{ + struct rt_list_node* node; + udevice_t device; + + /* parameter check */ + RT_ASSERT(dcd != RT_NULL); + + /* search a device in the the device list */ + for (node = device_list.next; node != &device_list; node = node->next) + { + device = (udevice_t)rt_list_entry(node, struct udevice, list); + if(device->dcd == dcd) return device; + } + + rt_kprintf("can't find device\n"); + return RT_NULL; +} + +/** + * This function will find an usb configuration object. + * + * @param device the usb device object. + * @param wValue the configuration number. + * + * @return an usb configuration object on found or RT_NULL on not found. + */ +uconfig_t rt_usbd_find_config(udevice_t device, rt_uint8_t value) +{ + struct rt_list_node* node; + uconfig_t cfg = RT_NULL; + + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_find_config\n")); + + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(value <= device->dev_desc.bNumConfigurations); + + /* search a configration in the the device */ + for (node = device->cfg_list.next; node != &device->cfg_list; node = node->next) + { + cfg = (uconfig_t)rt_list_entry(node, struct udevice, list); + if(cfg->cfg_desc.bConfigurationValue == value) + { + return cfg; + } + } + + rt_kprintf("can't find configuration %d\n", value); + return RT_NULL; +} + +/** + * This function will find an usb interface object. + * + * @param device the usb device object. + * @param wValue the interface number. + * + * @return an usb configuration object on found or RT_NULL on not found. + */ +uintf_t rt_usbd_find_interface(udevice_t device, rt_uint8_t value, ufunction_t *pfunc) +{ + struct rt_list_node *i, *j; + ufunction_t func; + uintf_t intf; + + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_find_interface\n")); + + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(value < device->nr_intf); + + /* search an interface in the current configuration */ + for (i=device->curr_cfg->func_list.next; + i!=&device->curr_cfg->func_list; i=i->next) + { + func = (ufunction_t)rt_list_entry(i, struct ufunction, list); + for(j=func->intf_list.next; j!=&func->intf_list; j=j->next) + { + intf = (uintf_t)rt_list_entry(j, struct uinterface, list); + if(intf->intf_num == value) + { + if (pfunc != RT_NULL) + *pfunc = func; + return intf; + } + } + } + + rt_kprintf("can't find interface %d\n", value); + return RT_NULL; +} + +/** + * This function will find an usb interface alternate setting object. + * + * @param device the usb device object. + * @param wValue the alternate setting number. + * + * @return an usb interface alternate setting object on found or RT_NULL on not found. + */ +ualtsetting_t rt_usbd_find_altsetting(uintf_t intf, rt_uint8_t value) +{ + struct rt_list_node *i; + ualtsetting_t setting; + + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_find_altsetting\n")); + + /* parameter check */ + RT_ASSERT(intf != RT_NULL); + + if(intf->curr_setting != RT_NULL) + { + /* if the wValue equal to the current alternate setting, then do not search */ + if(intf->curr_setting->intf_desc->bAlternateSetting == value) + return intf->curr_setting; + } + + /* search a setting in the alternate setting list */ + for(i=intf->setting_list.next; i!=&intf->setting_list; i=i->next) + { + setting =(ualtsetting_t)rt_list_entry(i, struct ualtsetting, list); + if(setting->intf_desc->bAlternateSetting == value) + return setting; + } + + rt_kprintf("can't find alternate setting %d\n", value); + return RT_NULL; +} + +/** + * This function will find an usb endpoint object. + * + * @param device the usb device object. + * @param ep_addr endpoint address. + * + * @return an usb endpoint object on found or RT_NULL on not found. + */ +uep_t rt_usbd_find_endpoint(udevice_t device, ufunction_t* pfunc, rt_uint8_t ep_addr) +{ + uep_t ep; + struct rt_list_node *i, *j, *k; + ufunction_t func; + uintf_t intf; + + /* parameter check */ + RT_ASSERT(device != RT_NULL); + + /* search a endpoint in the current configuration */ + for (i=device->curr_cfg->func_list.next; i!=&device->curr_cfg->func_list; i=i->next) + { + func = (ufunction_t)rt_list_entry(i, struct ufunction, list); + for(j=func->intf_list.next; j!=&func->intf_list; j=j->next) + { + intf = (uintf_t)rt_list_entry(j, struct uinterface, list); + for(k=intf->curr_setting->ep_list.next; + k!=&intf->curr_setting->ep_list; k=k->next) + { + ep = (uep_t)rt_list_entry(k, struct uendpoint, list); + if(EP_ADDRESS(ep) == ep_addr) + { + if (pfunc != RT_NULL) + *pfunc = func; + return ep; + } + } + } + } + + rt_kprintf("can't find endpoint 0x%x\n", ep_addr); + return RT_NULL; +} + +/** + * This function will add a configuration to an usb device. + * + * @param device the usb device object. + * @param cfg the configuration object. + * + * @return RT_EOK. + */ +rt_err_t rt_usbd_device_add_config(udevice_t device, uconfig_t cfg) +{ + struct rt_list_node *i, *j, *k, *m; + ufunction_t func; + uintf_t intf; + ualtsetting_t altsetting; + uep_t ep; + + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_device_add_config\n")); + + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(cfg != RT_NULL); + + /* set configuration number to the configuration descriptor */ + cfg->cfg_desc.bConfigurationValue = device->dev_desc.bNumConfigurations + 1; + device->dev_desc.bNumConfigurations++; + + for (i=cfg->func_list.next; i!=&cfg->func_list; i=i->next) + { + func = (ufunction_t)rt_list_entry(i, struct ufunction, list); + + for(j=func->intf_list.next; j!=&func->intf_list; j=j->next) + { + intf = (uintf_t)rt_list_entry(j, struct uinterface, list); + cfg->cfg_desc.bNumInterfaces++; + + for(k=intf->setting_list.next; k!=&intf->setting_list;k=k->next) + { + altsetting = (ualtsetting_t)rt_list_entry(k, struct ualtsetting, list); + + /* allocate address for every endpoint in the interface alternate setting */ + for(m=altsetting->ep_list.next; m!=&altsetting->ep_list; m=m->next) + { + ep = (uep_t)rt_list_entry(m, struct uendpoint, list); + if(rt_usbd_ep_assign(device, ep) != RT_EOK) + { + rt_kprintf("endpoint assign error\n"); + } + } + + /* construct complete configuration descriptor */ + rt_memcpy((void*)&cfg->cfg_desc.data[cfg->cfg_desc.wTotalLength - USB_DESC_LENGTH_CONFIG], + (void*)altsetting->desc, + altsetting->desc_size); + cfg->cfg_desc.wTotalLength += altsetting->desc_size; + } + } + } + + /* insert the configuration to the list */ + rt_list_insert_before(&device->cfg_list, &cfg->list); + + return RT_EOK; +} + +/** + * This function will add a function to a configuration. + * + * @param cfg the configuration object. + * @param func the function object. + * + * @return RT_EOK. + */ +rt_err_t rt_usbd_config_add_function(uconfig_t cfg, ufunction_t func) +{ + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_config_add_function\n")); + + /* parameter check */ + RT_ASSERT(cfg != RT_NULL); + RT_ASSERT(func != RT_NULL); + + /* insert the function to the list */ + rt_list_insert_before(&cfg->func_list, &func->list); + + return RT_EOK; +} + +/** + * This function will add an interface to a function. + * + * @param func the function object. + * @param intf the interface object. + * + * @return RT_EOK. + */ +rt_err_t rt_usbd_function_add_interface(ufunction_t func, uintf_t intf) +{ + + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_function_add_interface\n")); + + /* parameter check */ + RT_ASSERT(func != RT_NULL); + RT_ASSERT(intf != RT_NULL); + + /* insert the interface to the list */ + rt_list_insert_before(&func->intf_list, &intf->list); + + return RT_EOK; +} + +/** + * This function will add an alternate setting to an interface. + * + * @param intf the interface object. + * @param setting the alternate setting object. + * + * @return RT_EOK. + */ +rt_err_t rt_usbd_interface_add_altsetting(uintf_t intf, ualtsetting_t setting) +{ + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_interface_add_altsetting\n")); + + /* parameter check */ + RT_ASSERT(intf != RT_NULL); + RT_ASSERT(setting != RT_NULL); + + setting->intf_desc->bInterfaceNumber = intf->intf_num; + + /* insert the alternate setting to the list */ + rt_list_insert_before(&intf->setting_list, &setting->list); + + return RT_EOK; +} + +/** + * This function will add an endpoint to an alternate setting. + * + * @param setting the alternate setting object. + * @param ep the endpoint object. + * + * @return RT_EOK. + */ +rt_err_t rt_usbd_altsetting_add_endpoint(ualtsetting_t setting, uep_t ep) +{ + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_altsetting_add_endpoint\n")); + + /* parameter check */ + RT_ASSERT(setting != RT_NULL); + RT_ASSERT(ep != RT_NULL); + + /* insert the endpoint to the list */ + rt_list_insert_before(&setting->ep_list, &ep->list); + + return RT_EOK; +} + +rt_err_t rt_usbd_os_comp_id_desc_add_os_func_comp_id_desc(usb_os_comp_id_desc_t os_comp_id_desc, usb_os_func_comp_id_desc_t os_func_comp_id_desc) +{ + RT_ASSERT(os_comp_id_desc != RT_NULL); + RT_ASSERT(os_func_comp_id_desc != RT_NULL); + rt_list_insert_before(&os_comp_id_desc->func_desc, &os_func_comp_id_desc->list); + os_comp_id_desc->head_desc.bCount++; + return RT_EOK; +} + +/** + * This function will set an alternate setting for an interface. + * + * @param intf_desc the interface descriptor. + * @param wValue the alternate setting number. + * + * @return RT_EOK. + */ +rt_err_t rt_usbd_set_altsetting(uintf_t intf, rt_uint8_t value) +{ + ualtsetting_t setting; + + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_set_altsetting\n")); + + /* parameter check */ + RT_ASSERT(intf != RT_NULL); + + /* find an alternate setting */ + setting = rt_usbd_find_altsetting(intf, value); + + /* set as current alternate setting */ + intf->curr_setting = setting; + + return RT_EOK; +} + +/** + * This function will set a configuration for an usb device. + * + * @param device the usb device object. + * @param wValue the configuration number. + * + * @return RT_EOK. + */ +rt_err_t rt_usbd_set_config(udevice_t device, rt_uint8_t value) +{ + uconfig_t cfg; + + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbd_set_config\n")); + + /* parameter check */ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(value <= device->dev_desc.bNumConfigurations); + + /* find a configuration */ + cfg = rt_usbd_find_config(device, value); + + /* set as current configuration */ + device->curr_cfg = cfg; + + dcd_set_config(device->dcd, value); + + return RT_TRUE; +} + +/** + * This function will bRequest an IO transaction. + * + * @param device the usb device object. + * @param ep the endpoint object. + * @param req IO bRequest. + * + * @return RT_EOK. + */ +rt_size_t rt_usbd_io_request(udevice_t device, uep_t ep, uio_request_t req) +{ + rt_size_t size = 0; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(req != RT_NULL); + + if(ep->stalled == RT_FALSE) + { + switch(req->req_type) + { + case UIO_REQUEST_READ_BEST: + case UIO_REQUEST_READ_FULL: + ep->request.remain_size = ep->request.size; + size = rt_usbd_ep_read_prepare(device, ep, req->buffer, req->size); + break; + case UIO_REQUEST_WRITE: + ep->request.remain_size = ep->request.size; + size = rt_usbd_ep_write(device, ep, req->buffer, req->size); + break; + default: + rt_kprintf("unknown request type\n"); + break; + } + } + else + { + rt_list_insert_before(&ep->request_list, &req->list); + RT_DEBUG_LOG(RT_DEBUG_USB, ("suspend a request\n")); + } + + return size; +} + +/** + * This function will set feature for an usb device. + * + * @param device the usb device object. + * @param wValue the configuration number. + * + * @return RT_EOK. + */ +rt_err_t rt_usbd_set_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index) +{ + RT_ASSERT(device != RT_NULL); + + if (value == USB_FEATURE_DEV_REMOTE_WAKEUP) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("set feature remote wakeup\n")); + } + else if (value == USB_FEATURE_ENDPOINT_HALT) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("set feature stall\n")); + dcd_ep_set_stall(device->dcd, (rt_uint32_t)(index & 0xFF)); + } + + return RT_EOK; +} + +/** + * This function will clear feature for an usb device. + * + * @param device the usb device object. + * @param wValue the configuration number. + * + * @return RT_EOK. + */ +rt_err_t rt_usbd_clear_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index) +{ + RT_ASSERT(device != RT_NULL); + + if (value == USB_FEATURE_DEV_REMOTE_WAKEUP) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("clear feature remote wakeup\n")); + } + else if (value == USB_FEATURE_ENDPOINT_HALT) + { + RT_DEBUG_LOG(RT_DEBUG_USB, ("clear feature stall\n")); + dcd_ep_clear_stall(device->dcd, (rt_uint32_t)(index & 0xFF)); + } + + return RT_EOK; +} + +rt_err_t rt_usbd_ep0_set_stall(udevice_t device) +{ + RT_ASSERT(device != RT_NULL); + + return dcd_ep_set_stall(device->dcd, 0); +} + +rt_err_t rt_usbd_ep0_clear_stall(udevice_t device) +{ + RT_ASSERT(device != RT_NULL); + + return dcd_ep_clear_stall(device->dcd, 0); +} + +rt_err_t rt_usbd_ep_set_stall(udevice_t device, uep_t ep) +{ + rt_err_t ret; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(ep != RT_NULL); + RT_ASSERT(ep->ep_desc != RT_NULL); + + ret = dcd_ep_set_stall(device->dcd, EP_ADDRESS(ep)); + if(ret == RT_EOK) + { + ep->stalled = RT_TRUE; + } + + return ret; +} + +rt_err_t rt_usbd_ep_clear_stall(udevice_t device, uep_t ep) +{ + rt_err_t ret; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(ep != RT_NULL); + RT_ASSERT(ep->ep_desc != RT_NULL); + + ret = dcd_ep_clear_stall(device->dcd, EP_ADDRESS(ep)); + if(ret == RT_EOK) + { + ep->stalled = RT_FALSE; + } + + return ret; +} + +static rt_err_t rt_usbd_ep_assign(udevice_t device, uep_t ep) +{ + int i = 0; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(device->dcd != RT_NULL); + RT_ASSERT(device->dcd->ep_pool != RT_NULL); + RT_ASSERT(ep != RT_NULL); + RT_ASSERT(ep->ep_desc != RT_NULL); + + while(device->dcd->ep_pool[i].addr != 0xFF) + { + if(device->dcd->ep_pool[i].status == ID_UNASSIGNED && + ep->ep_desc->bmAttributes == device->dcd->ep_pool[i].type && (EP_ADDRESS(ep) & 0x80) == device->dcd->ep_pool[i].dir) + { + EP_ADDRESS(ep) |= device->dcd->ep_pool[i].addr; + ep->id = &device->dcd->ep_pool[i]; + device->dcd->ep_pool[i].status = ID_ASSIGNED; + + RT_DEBUG_LOG(RT_DEBUG_USB, ("assigned %d\n", device->dcd->ep_pool[i].addr)); + return RT_EOK; + } + + i++; + } + + return -RT_ERROR; +} + +rt_err_t rt_usbd_ep_unassign(udevice_t device, uep_t ep) +{ + RT_ASSERT(device != RT_NULL); + RT_ASSERT(device->dcd != RT_NULL); + RT_ASSERT(device->dcd->ep_pool != RT_NULL); + RT_ASSERT(ep != RT_NULL); + RT_ASSERT(ep->ep_desc != RT_NULL); + + ep->id->status = ID_UNASSIGNED; + + return RT_EOK; +} + +rt_err_t rt_usbd_ep0_setup_handler(udcd_t dcd, struct urequest* setup) +{ + struct udev_msg msg; + rt_size_t size; + + RT_ASSERT(dcd != RT_NULL); + + if(setup == RT_NULL) + { + size = dcd_ep_read(dcd, EP0_OUT_ADDR, (void*)&msg.content.setup); + if(size != sizeof(struct urequest)) + { + rt_kprintf("read setup packet error\n"); + return -RT_ERROR; + } + } + else + { + rt_memcpy((void*)&msg.content.setup, (void*)setup, sizeof(struct urequest)); + } + + msg.type = USB_MSG_SETUP_NOTIFY; + msg.dcd = dcd; + rt_usbd_event_signal(&msg); + + return RT_EOK; +} + +rt_err_t rt_usbd_ep0_in_handler(udcd_t dcd) +{ + rt_int32_t remain, mps; + + RT_ASSERT(dcd != RT_NULL); + + if (dcd->stage != STAGE_DIN) + return RT_EOK; + + mps = dcd->ep0.id->maxpacket; + dcd->ep0.request.remain_size -= mps; + remain = dcd->ep0.request.remain_size; + + if (remain > 0) + { + if (remain >= mps) + { + remain = mps; + } + + dcd->ep0.request.buffer += mps; + dcd_ep_write(dcd, EP0_IN_ADDR, dcd->ep0.request.buffer, remain); + } + else + { + /* last packet is MPS multiple, so send ZLP packet */ + if ((remain == 0) && (dcd->ep0.request.size > 0)) + { + dcd->ep0.request.size = 0; + dcd_ep_write(dcd, EP0_IN_ADDR, RT_NULL, 0); + } + else + { + /* receive status */ + dcd->stage = STAGE_STATUS_OUT; + dcd_ep_read_prepare(dcd, EP0_OUT_ADDR, RT_NULL, 0); + } + } + + return RT_EOK; +} + +rt_err_t rt_usbd_ep0_out_handler(udcd_t dcd, rt_size_t size) +{ + struct udev_msg msg; + + RT_ASSERT(dcd != RT_NULL); + + msg.type = USB_MSG_EP0_OUT; + msg.dcd = dcd; + msg.content.ep_msg.size = size; + rt_usbd_event_signal(&msg); + + return RT_EOK; +} + +rt_err_t rt_usbd_ep_in_handler(udcd_t dcd, rt_uint8_t address, rt_size_t size) +{ + struct udev_msg msg; + + RT_ASSERT(dcd != RT_NULL); + + msg.type = USB_MSG_DATA_NOTIFY; + msg.dcd = dcd; + msg.content.ep_msg.ep_addr = address; + msg.content.ep_msg.size = size; + rt_usbd_event_signal(&msg); + + return RT_EOK; +} + +rt_err_t rt_usbd_ep_out_handler(udcd_t dcd, rt_uint8_t address, rt_size_t size) +{ + struct udev_msg msg; + + RT_ASSERT(dcd != RT_NULL); + + msg.type = USB_MSG_DATA_NOTIFY; + msg.dcd = dcd; + msg.content.ep_msg.ep_addr = address; + msg.content.ep_msg.size = size; + rt_usbd_event_signal(&msg); + + return RT_EOK; +} + +rt_err_t rt_usbd_reset_handler(udcd_t dcd) +{ + struct udev_msg msg; + + RT_ASSERT(dcd != RT_NULL); + + msg.type = USB_MSG_RESET; + msg.dcd = dcd; + rt_usbd_event_signal(&msg); + + return RT_EOK; +} + +rt_err_t rt_usbd_connect_handler(udcd_t dcd) +{ + struct udev_msg msg; + + RT_ASSERT(dcd != RT_NULL); + + msg.type = USB_MSG_PLUG_IN; + msg.dcd = dcd; + rt_usbd_event_signal(&msg); + + return RT_EOK; +} + +rt_err_t rt_usbd_disconnect_handler(udcd_t dcd) +{ + struct udev_msg msg; + + RT_ASSERT(dcd != RT_NULL); + + msg.type = USB_MSG_PLUG_OUT; + msg.dcd = dcd; + rt_usbd_event_signal(&msg); + + return RT_EOK; +} + +rt_err_t rt_usbd_sof_handler(udcd_t dcd) +{ + struct udev_msg msg; + + RT_ASSERT(dcd != RT_NULL); + + msg.type = USB_MSG_SOF; + msg.dcd = dcd; + rt_usbd_event_signal(&msg); + + return RT_EOK; +} + +rt_size_t rt_usbd_ep0_write(udevice_t device, void *buffer, rt_size_t size) +{ + uep_t ep0; + rt_size_t sent_size = 0; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(device->dcd != RT_NULL); + RT_ASSERT(buffer != RT_NULL); + RT_ASSERT(size > 0); + + ep0 = &device->dcd->ep0; + ep0->request.size = size; + ep0->request.buffer = (rt_uint8_t *)buffer; + ep0->request.remain_size = size; + if(size >= ep0->id->maxpacket) + { + sent_size = ep0->id->maxpacket; + } + else + { + sent_size = size; + } + device->dcd->stage = STAGE_DIN; + + return dcd_ep_write(device->dcd, EP0_IN_ADDR, ep0->request.buffer, sent_size); +} + +rt_size_t rt_usbd_ep0_read(udevice_t device, void *buffer, rt_size_t size, + rt_err_t (*rx_ind)(udevice_t device, rt_size_t size)) +{ + uep_t ep0; + rt_size_t read_size = 0; + + RT_ASSERT(device != RT_NULL); + RT_ASSERT(device->dcd != RT_NULL); + RT_ASSERT(buffer != RT_NULL); + + ep0 = &device->dcd->ep0; + ep0->request.buffer = (rt_uint8_t *)buffer; + ep0->request.remain_size = size; + ep0->rx_indicate = rx_ind; + if(size >= ep0->id->maxpacket) + { + read_size = ep0->id->maxpacket; + } + else + { + read_size = size; + } + device->dcd->stage = STAGE_DOUT; + dcd_ep_read_prepare(device->dcd, EP0_OUT_ADDR, buffer, read_size); + + return size; +} + +static struct rt_messagequeue usb_mq; + +/** + * This function is the main entry of usb device thread, it is in charge of + * processing all messages received from the usb message buffer. + * + * @param parameter the parameter of the usb device thread. + * + * @return none. + */ +static void rt_usbd_thread_entry(void* parameter) +{ + while(1) + { + struct udev_msg msg; + udevice_t device; + + /* receive message */ + if(rt_mq_recv(&usb_mq, &msg, sizeof(struct udev_msg), + RT_WAITING_FOREVER) != RT_EOK ) + continue; + + device = rt_usbd_find_device(msg.dcd); + if(device == RT_NULL) + { + rt_kprintf("invalid usb device\n"); + continue; + } + + RT_DEBUG_LOG(RT_DEBUG_USB, ("message type %d\n", msg.type)); + + switch (msg.type) + { + case USB_MSG_SOF: + _sof_notify(device); + break; + case USB_MSG_DATA_NOTIFY: + /* some buggy drivers will have USB_MSG_DATA_NOTIFY before the core + * got configured. */ + _data_notify(device, &msg.content.ep_msg); + break; + case USB_MSG_SETUP_NOTIFY: + _setup_request(device, &msg.content.setup); + break; + case USB_MSG_EP0_OUT: + _ep0_out_notify(device, &msg.content.ep_msg); + break; + case USB_MSG_RESET: + RT_DEBUG_LOG(RT_DEBUG_USB, ("reset %d\n", device->state)); + if (device->state == USB_STATE_ADDRESS || device->state == USB_STATE_CONFIGURED) + _stop_notify(device); + device->state = USB_STATE_NOTATTACHED; + break; + case USB_MSG_PLUG_IN: + device->state = USB_STATE_ATTACHED; + break; + case USB_MSG_PLUG_OUT: + device->state = USB_STATE_NOTATTACHED; + _stop_notify(device); + break; + default: + rt_kprintf("unknown msg type %d\n", msg.type); + break; + } + } +} + +/** + * This function will post an message to usb message queue, + * + * @param msg the message to be posted + * @param size the size of the message . + * + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_usbd_event_signal(struct udev_msg* msg) +{ + RT_ASSERT(msg != RT_NULL); + + /* send message to usb message queue */ + return rt_mq_send(&usb_mq, (void*)msg, sizeof(struct udev_msg)); +} + + +ALIGN(RT_ALIGN_SIZE) +static rt_uint8_t usb_thread_stack[RT_USBD_THREAD_STACK_SZ]; +static struct rt_thread usb_thread; +#define USBD_MQ_MSG_SZ 32 +#define USBD_MQ_MAX_MSG 16 +/* internal of the message queue: every message is associated with a pointer, + * so in order to recveive USBD_MQ_MAX_MSG messages, we have to allocate more + * than USBD_MQ_MSG_SZ*USBD_MQ_MAX_MSG memory. */ +static rt_uint8_t usb_mq_pool[(USBD_MQ_MSG_SZ+sizeof(void*))*USBD_MQ_MAX_MSG]; + +/** + * This function will initialize usb device thread. + * + * @return none. + * + */ +rt_err_t rt_usbd_core_init(void) +{ + rt_list_init(&device_list); + + /* create an usb message queue */ + rt_mq_init(&usb_mq, + "usbd", + usb_mq_pool, USBD_MQ_MSG_SZ, + sizeof(usb_mq_pool), + RT_IPC_FLAG_FIFO); + + /* init usb device thread */ + rt_thread_init(&usb_thread, + "usbd", + rt_usbd_thread_entry, RT_NULL, + usb_thread_stack, RT_USBD_THREAD_STACK_SZ, + RT_USBD_THREAD_PRIO, 20); + /* rt_thread_init should always be OK, so start the thread without further + * checking. */ + return rt_thread_startup(&usb_thread); +} + diff --git a/components/drivers/usb/usbhost/SConscript b/components/drivers/usb/usbhost/SConscript index f497f8868d..081c732819 100644 --- a/components/drivers/usb/usbhost/SConscript +++ b/components/drivers/usb/usbhost/SConscript @@ -3,7 +3,7 @@ from building import * cwd = GetCurrentDir() src = Split(""" -core/uh_core.c +core/usbhost_core.c core/driver.c core/usbhost.c core/hub.c diff --git a/components/drivers/usb/usbhost/core/uh_core.c b/components/drivers/usb/usbhost/core/uh_core.c deleted file mode 100644 index 71341a33c3..0000000000 --- a/components/drivers/usb/usbhost/core/uh_core.c +++ /dev/null @@ -1,576 +0,0 @@ -/* - * Copyright (c) 2006-2018, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2011-12-12 Yi Qiu first version - */ - -#include -#include - -static struct uinstance dev[USB_MAX_DEVICE]; - -/** - * This function will allocate an usb device instance from system. - * - * @param parent the hub instance to which the new allocated device attached. - * @param port the hub port. - * - * @return the allocate instance on successful, or RT_NULL on failure. - */ -uinst_t rt_usbh_alloc_instance(uhcd_t uhcd) -{ - int i; - - /* lock scheduler */ - rt_enter_critical(); - - for(i=0; idev_desc; - - /* alloc address 0 ep0 pipe*/ - ep0_out_desc.wMaxPacketSize = 8; - ep0_in_desc.wMaxPacketSize = 8; - rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_out, device, &ep0_out_desc); - rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_in, device, &ep0_in_desc); - - RT_DEBUG_LOG(RT_DEBUG_USB, ("start enumnation\n")); - - /* get device descriptor head */ - ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_DEVICE, (void*)dev_desc, 8); - if(ret != RT_EOK) - { - rt_kprintf("get device descriptor head failed\n"); - return ret; - } - - /* reset bus */ - rt_usbh_hub_reset_port(device->parent_hub, device->port); - rt_thread_delay(2); - rt_usbh_hub_clear_port_feature(device->parent_hub, i + 1, PORT_FEAT_C_CONNECTION); - /* set device address */ - ret = rt_usbh_set_address(device); - if(ret != RT_EOK) - { - rt_kprintf("set device address failed\n"); - return ret; - } - /* free address 0 ep0 pipe*/ - - rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_out); - rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_in); - - /* set device max packet size */ - ep0_out_desc.wMaxPacketSize = device->dev_desc.bMaxPacketSize0; - ep0_in_desc.wMaxPacketSize = device->dev_desc.bMaxPacketSize0; - - /* alloc true address ep0 pipe*/ - rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_out, device, &ep0_out_desc); - rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_in, device, &ep0_in_desc); - RT_DEBUG_LOG(RT_DEBUG_USB, ("get device descriptor length %d\n", - dev_desc->bLength)); - - /* get full device descriptor again */ - ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_DEVICE, (void*)dev_desc, dev_desc->bLength); - if(ret != RT_EOK) - { - rt_kprintf("get full device descriptor failed\n"); - return ret; - } - - RT_DEBUG_LOG(RT_DEBUG_USB, ("Vendor ID 0x%x\n", dev_desc->idVendor)); - RT_DEBUG_LOG(RT_DEBUG_USB, ("Product ID 0x%x\n", dev_desc->idProduct)); - - /* get configuration descriptor head */ - ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_CONFIGURATION, &cfg_desc, 18); - if(ret != RT_EOK) - { - rt_kprintf("get configuration descriptor head failed\n"); - return ret; - } - - /* alloc memory for configuration descriptor */ - device->cfg_desc = (ucfg_desc_t)rt_malloc(cfg_desc.wTotalLength); - rt_memset(device->cfg_desc, 0, cfg_desc.wTotalLength); - - /* get full configuration descriptor */ - ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_CONFIGURATION, - device->cfg_desc, cfg_desc.wTotalLength); - if(ret != RT_EOK) - { - rt_kprintf("get full configuration descriptor failed\n"); - return ret; - } - - /* set configuration */ - ret = rt_usbh_set_configure(device, 1); - if(ret != RT_EOK) - { - return ret; - } - for(i=0; icfg_desc->bNumInterfaces; i++) - { - /* get interface descriptor through configuration descriptor */ - ret = rt_usbh_get_interface_descriptor(device->cfg_desc, i, &intf_desc); - if(ret != RT_EOK) - { - rt_kprintf("rt_usb_get_interface_descriptor error\n"); - return -RT_ERROR; - } - - RT_DEBUG_LOG(RT_DEBUG_USB, ("interface class 0x%x, subclass 0x%x\n", - intf_desc->bInterfaceClass, - intf_desc->bInterfaceSubClass)); - /* alloc pipe*/ - for(ep_index = 0; ep_index < intf_desc->bNumEndpoints; ep_index++) - { - rt_usbh_get_endpoint_descriptor(intf_desc, ep_index, &ep_desc); - if(ep_desc != RT_NULL) - { - if(rt_usb_hcd_alloc_pipe(device->hcd, &pipe, device, ep_desc) != RT_EOK) - { - rt_kprintf("alloc pipe failed\n"); - return RT_ERROR; - } - rt_usb_instance_add_pipe(device,pipe); - } - else - { - rt_kprintf("get endpoint desc failed\n"); - return RT_ERROR; - } - } - /* find driver by class code found in interface descriptor */ - drv = rt_usbh_class_driver_find(intf_desc->bInterfaceClass, - intf_desc->bInterfaceSubClass); - - if(drv != RT_NULL) - { - /* allocate memory for interface device */ - device->intf[i] = (struct uhintf*)rt_malloc(sizeof(struct uhintf)); - device->intf[i]->drv = drv; - device->intf[i]->device = device; - device->intf[i]->intf_desc = intf_desc; - device->intf[i]->user_data = RT_NULL; - - /* open usb class driver */ - ret = rt_usbh_class_driver_enable(drv, (void*)device->intf[i]); - if(ret != RT_EOK) - { - rt_kprintf("interface %d run class driver error\n", i); - } - } - else - { - rt_kprintf("find usb device driver failed\n"); - continue; - } - } - - return RT_EOK; -} - -/** - * This function will detach an usb device instance from its host controller, - * and release all resource. - * - * @param device the usb device instance. - * - * @return the error code, RT_EOK on successfully. - */ -rt_err_t rt_usbh_detach_instance(uinst_t device) -{ - int i = 0; - rt_list_t * l; - if(device == RT_NULL) - { - rt_kprintf("no usb instance to detach\n"); - return -RT_ERROR; - } - - /* free configration descriptor */ - if (device->cfg_desc) { - for (i = 0; i < device->cfg_desc->bNumInterfaces; i++) - { - if (device->intf[i] == RT_NULL) continue; - if (device->intf[i]->drv == RT_NULL) continue; - - RT_ASSERT(device->intf[i]->device == device); - - RT_DEBUG_LOG(RT_DEBUG_USB, ("free interface instance %d\n", i)); - rt_usbh_class_driver_disable(device->intf[i]->drv, (void*)device->intf[i]); - rt_free(device->intf[i]); - } - rt_free(device->cfg_desc); - } - - rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_out); - rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_in); - - while(device->pipe.next!= &device->pipe) - { - l = device->pipe.next; - rt_list_remove(l); - rt_usb_hcd_free_pipe(device->hcd,rt_list_entry(l,struct upipe,list)); - } - rt_memset(device, 0, sizeof(struct uinstance)); - - return RT_EOK; -} - -/** - * This function will do USB_REQ_GET_DESCRIPTO' bRequest for the usb device instance, - * - * @param device the usb device instance. - * @param type the type of descriptor bRequest. - * @param buffer the data buffer to save requested data - * @param nbytes the size of buffer - * - * @return the error code, RT_EOK on successfully. - */ -rt_err_t rt_usbh_get_descriptor(uinst_t device, rt_uint8_t type, void* buffer, - int nbytes) -{ - struct urequest setup; - int timeout = USB_TIMEOUT_BASIC; - - RT_ASSERT(device != RT_NULL); - - setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_STANDARD | - USB_REQ_TYPE_DEVICE; - setup.bRequest = USB_REQ_GET_DESCRIPTOR; - setup.wIndex = 0; - setup.wLength = nbytes; - setup.wValue = type << 8; - - if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8) - { - if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, nbytes, timeout) == nbytes) - { - if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) == 0) - { - return RT_EOK; - } - } - } - return RT_ERROR; -} - -/** - * This function will set an address to the usb device. - * - * @param device the usb device instance. - * - * @return the error code, RT_EOK on successfully. - */ -rt_err_t rt_usbh_set_address(uinst_t device) -{ - struct urequest setup; - int timeout = USB_TIMEOUT_BASIC; - - RT_ASSERT(device != RT_NULL); - - RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usb_set_address\n")); - - setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD | - USB_REQ_TYPE_DEVICE; - setup.bRequest = USB_REQ_SET_ADDRESS; - setup.wIndex = 0; - setup.wLength = 0; - setup.wValue = device->index; - - if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8) - { - return RT_ERROR; - } - if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) == 0) - { - device->address = device->index; - } - - return RT_EOK; -} - -/** - * This function will set a configuration to the usb device. - * - * @param device the usb device instance. - * @param config the configuration number. - * - * @return the error code, RT_EOK on successfully. - */ -rt_err_t rt_usbh_set_configure(uinst_t device, int config) -{ - struct urequest setup; - int timeout = USB_TIMEOUT_BASIC; - - /* check parameter */ - RT_ASSERT(device != RT_NULL); - - setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD | - USB_REQ_TYPE_DEVICE; - setup.bRequest = USB_REQ_SET_CONFIGURATION; - setup.wIndex = 0; - setup.wLength = 0; - setup.wValue = config; - - if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8) - { - return RT_ERROR; - } - if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) != 0) - { - return RT_ERROR; - } - return RT_EOK; -} - -/** - * This function will set an interface to the usb device. - * - * @param device the usb device instance. - * @param intf the interface number. - * - * @return the error code, RT_EOK on successfully. - */ -rt_err_t rt_usbh_set_interface(uinst_t device, int intf) -{ - struct urequest setup; - int timeout = USB_TIMEOUT_BASIC; - - /* check parameter */ - RT_ASSERT(device != RT_NULL); - - setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD | - USB_REQ_TYPE_INTERFACE; - setup.bRequest = USB_REQ_SET_INTERFACE; - setup.wIndex = 0; - setup.wLength = 0; - setup.wValue = intf; - - if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8) - { - return RT_ERROR; - } - - return RT_EOK; -} - -/** - * This function will clear feature for the endpoint of the usb device. - * - * @param device the usb device instance. - * @param endpoint the endpoint number of the usb device. - * - * @return the error code, RT_EOK on successfully. - */ -rt_err_t rt_usbh_clear_feature(uinst_t device, int endpoint, int feature) -{ - struct urequest setup; - int timeout = USB_TIMEOUT_BASIC; - - /* check parameter */ - RT_ASSERT(device != RT_NULL); - - setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD | - USB_REQ_TYPE_ENDPOINT; - setup.bRequest = USB_REQ_CLEAR_FEATURE; - setup.wIndex = endpoint; - setup.wLength = 0; - setup.wValue = feature; - - if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8) - { - return RT_ERROR; - } - - return RT_EOK; -} - -/** - * This function will get an interface descriptor from the configuration descriptor. - * - * @param cfg_desc the point of configuration descriptor structure. - * @param num the number of interface descriptor. - * @intf_desc the point of interface descriptor point. - * - * @return the error code, RT_EOK on successfully. - */ -rt_err_t rt_usbh_get_interface_descriptor(ucfg_desc_t cfg_desc, int num, - uintf_desc_t* intf_desc) -{ - rt_uint32_t ptr, depth = 0; - udesc_t desc; - - /* check parameter */ - RT_ASSERT(cfg_desc != RT_NULL); - - ptr = (rt_uint32_t)cfg_desc + cfg_desc->bLength; - while(ptr < (rt_uint32_t)cfg_desc + cfg_desc->wTotalLength) - { - if(depth++ > 0x20) - { - *intf_desc = RT_NULL; - return -RT_EIO; - } - desc = (udesc_t)ptr; - if(desc->type == USB_DESC_TYPE_INTERFACE) - { - if(((uintf_desc_t)desc)->bInterfaceNumber == num) - { - *intf_desc = (uintf_desc_t)desc; - - RT_DEBUG_LOG(RT_DEBUG_USB, - ("rt_usb_get_interface_descriptor: %d\n", num)); - return RT_EOK; - } - } - ptr = (rt_uint32_t)desc + desc->bLength; - } - - rt_kprintf("rt_usb_get_interface_descriptor %d failed\n", num); - return -RT_EIO; -} - -/** - * This function will get an endpoint descriptor from the interface descriptor. - * - * @param intf_desc the point of interface descriptor structure. - * @param num the number of endpoint descriptor. - * @param ep_desc the point of endpoint descriptor point. - * - * @return the error code, RT_EOK on successfully. - */ -rt_err_t rt_usbh_get_endpoint_descriptor(uintf_desc_t intf_desc, int num, - uep_desc_t* ep_desc) -{ - int count = 0, depth = 0; - rt_uint32_t ptr; - udesc_t desc; - - /* check parameter */ - RT_ASSERT(intf_desc != RT_NULL); - RT_ASSERT(num < intf_desc->bNumEndpoints); - *ep_desc = RT_NULL; - - ptr = (rt_uint32_t)intf_desc + intf_desc->bLength; - while(count < intf_desc->bNumEndpoints) - { - if(depth++ > 0x20) - { - *ep_desc = RT_NULL; - return -RT_EIO; - } - desc = (udesc_t)ptr; - if(desc->type == USB_DESC_TYPE_ENDPOINT) - { - if(num == count) - { - *ep_desc = (uep_desc_t)desc; - - RT_DEBUG_LOG(RT_DEBUG_USB, - ("rt_usb_get_endpoint_descriptor: %d\n", num)); - return RT_EOK; - } - else count++; - } - ptr = (rt_uint32_t)desc + desc->bLength; - } - - rt_kprintf("rt_usb_get_endpoint_descriptor %d failed\n", num); - return -RT_EIO; -} - -int rt_usb_hcd_pipe_xfer(uhcd_t hcd, upipe_t pipe, void* buffer, int nbytes, int timeout) -{ - rt_size_t remain_size; - rt_size_t send_size; - remain_size = nbytes; - rt_uint8_t * pbuffer = (rt_uint8_t *)buffer; - do - { - RT_DEBUG_LOG(RT_DEBUG_USB,("pipe transform remain size,: %d\n", remain_size)); - send_size = (remain_size > pipe->ep.wMaxPacketSize) ? pipe->ep.wMaxPacketSize : remain_size; - if(hcd->ops->pipe_xfer(pipe, USBH_PID_DATA, pbuffer, send_size, timeout) == send_size) - { - remain_size -= send_size; - pbuffer += send_size; - } - else - { - return 0; - } - }while(remain_size > 0); - return nbytes; -} diff --git a/components/drivers/usb/usbhost/core/usbhost_core.c b/components/drivers/usb/usbhost/core/usbhost_core.c new file mode 100644 index 0000000000..71341a33c3 --- /dev/null +++ b/components/drivers/usb/usbhost/core/usbhost_core.c @@ -0,0 +1,576 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2011-12-12 Yi Qiu first version + */ + +#include +#include + +static struct uinstance dev[USB_MAX_DEVICE]; + +/** + * This function will allocate an usb device instance from system. + * + * @param parent the hub instance to which the new allocated device attached. + * @param port the hub port. + * + * @return the allocate instance on successful, or RT_NULL on failure. + */ +uinst_t rt_usbh_alloc_instance(uhcd_t uhcd) +{ + int i; + + /* lock scheduler */ + rt_enter_critical(); + + for(i=0; idev_desc; + + /* alloc address 0 ep0 pipe*/ + ep0_out_desc.wMaxPacketSize = 8; + ep0_in_desc.wMaxPacketSize = 8; + rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_out, device, &ep0_out_desc); + rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_in, device, &ep0_in_desc); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("start enumnation\n")); + + /* get device descriptor head */ + ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_DEVICE, (void*)dev_desc, 8); + if(ret != RT_EOK) + { + rt_kprintf("get device descriptor head failed\n"); + return ret; + } + + /* reset bus */ + rt_usbh_hub_reset_port(device->parent_hub, device->port); + rt_thread_delay(2); + rt_usbh_hub_clear_port_feature(device->parent_hub, i + 1, PORT_FEAT_C_CONNECTION); + /* set device address */ + ret = rt_usbh_set_address(device); + if(ret != RT_EOK) + { + rt_kprintf("set device address failed\n"); + return ret; + } + /* free address 0 ep0 pipe*/ + + rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_out); + rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_in); + + /* set device max packet size */ + ep0_out_desc.wMaxPacketSize = device->dev_desc.bMaxPacketSize0; + ep0_in_desc.wMaxPacketSize = device->dev_desc.bMaxPacketSize0; + + /* alloc true address ep0 pipe*/ + rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_out, device, &ep0_out_desc); + rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_in, device, &ep0_in_desc); + RT_DEBUG_LOG(RT_DEBUG_USB, ("get device descriptor length %d\n", + dev_desc->bLength)); + + /* get full device descriptor again */ + ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_DEVICE, (void*)dev_desc, dev_desc->bLength); + if(ret != RT_EOK) + { + rt_kprintf("get full device descriptor failed\n"); + return ret; + } + + RT_DEBUG_LOG(RT_DEBUG_USB, ("Vendor ID 0x%x\n", dev_desc->idVendor)); + RT_DEBUG_LOG(RT_DEBUG_USB, ("Product ID 0x%x\n", dev_desc->idProduct)); + + /* get configuration descriptor head */ + ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_CONFIGURATION, &cfg_desc, 18); + if(ret != RT_EOK) + { + rt_kprintf("get configuration descriptor head failed\n"); + return ret; + } + + /* alloc memory for configuration descriptor */ + device->cfg_desc = (ucfg_desc_t)rt_malloc(cfg_desc.wTotalLength); + rt_memset(device->cfg_desc, 0, cfg_desc.wTotalLength); + + /* get full configuration descriptor */ + ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_CONFIGURATION, + device->cfg_desc, cfg_desc.wTotalLength); + if(ret != RT_EOK) + { + rt_kprintf("get full configuration descriptor failed\n"); + return ret; + } + + /* set configuration */ + ret = rt_usbh_set_configure(device, 1); + if(ret != RT_EOK) + { + return ret; + } + for(i=0; icfg_desc->bNumInterfaces; i++) + { + /* get interface descriptor through configuration descriptor */ + ret = rt_usbh_get_interface_descriptor(device->cfg_desc, i, &intf_desc); + if(ret != RT_EOK) + { + rt_kprintf("rt_usb_get_interface_descriptor error\n"); + return -RT_ERROR; + } + + RT_DEBUG_LOG(RT_DEBUG_USB, ("interface class 0x%x, subclass 0x%x\n", + intf_desc->bInterfaceClass, + intf_desc->bInterfaceSubClass)); + /* alloc pipe*/ + for(ep_index = 0; ep_index < intf_desc->bNumEndpoints; ep_index++) + { + rt_usbh_get_endpoint_descriptor(intf_desc, ep_index, &ep_desc); + if(ep_desc != RT_NULL) + { + if(rt_usb_hcd_alloc_pipe(device->hcd, &pipe, device, ep_desc) != RT_EOK) + { + rt_kprintf("alloc pipe failed\n"); + return RT_ERROR; + } + rt_usb_instance_add_pipe(device,pipe); + } + else + { + rt_kprintf("get endpoint desc failed\n"); + return RT_ERROR; + } + } + /* find driver by class code found in interface descriptor */ + drv = rt_usbh_class_driver_find(intf_desc->bInterfaceClass, + intf_desc->bInterfaceSubClass); + + if(drv != RT_NULL) + { + /* allocate memory for interface device */ + device->intf[i] = (struct uhintf*)rt_malloc(sizeof(struct uhintf)); + device->intf[i]->drv = drv; + device->intf[i]->device = device; + device->intf[i]->intf_desc = intf_desc; + device->intf[i]->user_data = RT_NULL; + + /* open usb class driver */ + ret = rt_usbh_class_driver_enable(drv, (void*)device->intf[i]); + if(ret != RT_EOK) + { + rt_kprintf("interface %d run class driver error\n", i); + } + } + else + { + rt_kprintf("find usb device driver failed\n"); + continue; + } + } + + return RT_EOK; +} + +/** + * This function will detach an usb device instance from its host controller, + * and release all resource. + * + * @param device the usb device instance. + * + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_usbh_detach_instance(uinst_t device) +{ + int i = 0; + rt_list_t * l; + if(device == RT_NULL) + { + rt_kprintf("no usb instance to detach\n"); + return -RT_ERROR; + } + + /* free configration descriptor */ + if (device->cfg_desc) { + for (i = 0; i < device->cfg_desc->bNumInterfaces; i++) + { + if (device->intf[i] == RT_NULL) continue; + if (device->intf[i]->drv == RT_NULL) continue; + + RT_ASSERT(device->intf[i]->device == device); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("free interface instance %d\n", i)); + rt_usbh_class_driver_disable(device->intf[i]->drv, (void*)device->intf[i]); + rt_free(device->intf[i]); + } + rt_free(device->cfg_desc); + } + + rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_out); + rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_in); + + while(device->pipe.next!= &device->pipe) + { + l = device->pipe.next; + rt_list_remove(l); + rt_usb_hcd_free_pipe(device->hcd,rt_list_entry(l,struct upipe,list)); + } + rt_memset(device, 0, sizeof(struct uinstance)); + + return RT_EOK; +} + +/** + * This function will do USB_REQ_GET_DESCRIPTO' bRequest for the usb device instance, + * + * @param device the usb device instance. + * @param type the type of descriptor bRequest. + * @param buffer the data buffer to save requested data + * @param nbytes the size of buffer + * + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_usbh_get_descriptor(uinst_t device, rt_uint8_t type, void* buffer, + int nbytes) +{ + struct urequest setup; + int timeout = USB_TIMEOUT_BASIC; + + RT_ASSERT(device != RT_NULL); + + setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_STANDARD | + USB_REQ_TYPE_DEVICE; + setup.bRequest = USB_REQ_GET_DESCRIPTOR; + setup.wIndex = 0; + setup.wLength = nbytes; + setup.wValue = type << 8; + + if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8) + { + if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, nbytes, timeout) == nbytes) + { + if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) == 0) + { + return RT_EOK; + } + } + } + return RT_ERROR; +} + +/** + * This function will set an address to the usb device. + * + * @param device the usb device instance. + * + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_usbh_set_address(uinst_t device) +{ + struct urequest setup; + int timeout = USB_TIMEOUT_BASIC; + + RT_ASSERT(device != RT_NULL); + + RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usb_set_address\n")); + + setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD | + USB_REQ_TYPE_DEVICE; + setup.bRequest = USB_REQ_SET_ADDRESS; + setup.wIndex = 0; + setup.wLength = 0; + setup.wValue = device->index; + + if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8) + { + return RT_ERROR; + } + if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) == 0) + { + device->address = device->index; + } + + return RT_EOK; +} + +/** + * This function will set a configuration to the usb device. + * + * @param device the usb device instance. + * @param config the configuration number. + * + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_usbh_set_configure(uinst_t device, int config) +{ + struct urequest setup; + int timeout = USB_TIMEOUT_BASIC; + + /* check parameter */ + RT_ASSERT(device != RT_NULL); + + setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD | + USB_REQ_TYPE_DEVICE; + setup.bRequest = USB_REQ_SET_CONFIGURATION; + setup.wIndex = 0; + setup.wLength = 0; + setup.wValue = config; + + if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8) + { + return RT_ERROR; + } + if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) != 0) + { + return RT_ERROR; + } + return RT_EOK; +} + +/** + * This function will set an interface to the usb device. + * + * @param device the usb device instance. + * @param intf the interface number. + * + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_usbh_set_interface(uinst_t device, int intf) +{ + struct urequest setup; + int timeout = USB_TIMEOUT_BASIC; + + /* check parameter */ + RT_ASSERT(device != RT_NULL); + + setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD | + USB_REQ_TYPE_INTERFACE; + setup.bRequest = USB_REQ_SET_INTERFACE; + setup.wIndex = 0; + setup.wLength = 0; + setup.wValue = intf; + + if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8) + { + return RT_ERROR; + } + + return RT_EOK; +} + +/** + * This function will clear feature for the endpoint of the usb device. + * + * @param device the usb device instance. + * @param endpoint the endpoint number of the usb device. + * + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_usbh_clear_feature(uinst_t device, int endpoint, int feature) +{ + struct urequest setup; + int timeout = USB_TIMEOUT_BASIC; + + /* check parameter */ + RT_ASSERT(device != RT_NULL); + + setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD | + USB_REQ_TYPE_ENDPOINT; + setup.bRequest = USB_REQ_CLEAR_FEATURE; + setup.wIndex = endpoint; + setup.wLength = 0; + setup.wValue = feature; + + if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8) + { + return RT_ERROR; + } + + return RT_EOK; +} + +/** + * This function will get an interface descriptor from the configuration descriptor. + * + * @param cfg_desc the point of configuration descriptor structure. + * @param num the number of interface descriptor. + * @intf_desc the point of interface descriptor point. + * + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_usbh_get_interface_descriptor(ucfg_desc_t cfg_desc, int num, + uintf_desc_t* intf_desc) +{ + rt_uint32_t ptr, depth = 0; + udesc_t desc; + + /* check parameter */ + RT_ASSERT(cfg_desc != RT_NULL); + + ptr = (rt_uint32_t)cfg_desc + cfg_desc->bLength; + while(ptr < (rt_uint32_t)cfg_desc + cfg_desc->wTotalLength) + { + if(depth++ > 0x20) + { + *intf_desc = RT_NULL; + return -RT_EIO; + } + desc = (udesc_t)ptr; + if(desc->type == USB_DESC_TYPE_INTERFACE) + { + if(((uintf_desc_t)desc)->bInterfaceNumber == num) + { + *intf_desc = (uintf_desc_t)desc; + + RT_DEBUG_LOG(RT_DEBUG_USB, + ("rt_usb_get_interface_descriptor: %d\n", num)); + return RT_EOK; + } + } + ptr = (rt_uint32_t)desc + desc->bLength; + } + + rt_kprintf("rt_usb_get_interface_descriptor %d failed\n", num); + return -RT_EIO; +} + +/** + * This function will get an endpoint descriptor from the interface descriptor. + * + * @param intf_desc the point of interface descriptor structure. + * @param num the number of endpoint descriptor. + * @param ep_desc the point of endpoint descriptor point. + * + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_usbh_get_endpoint_descriptor(uintf_desc_t intf_desc, int num, + uep_desc_t* ep_desc) +{ + int count = 0, depth = 0; + rt_uint32_t ptr; + udesc_t desc; + + /* check parameter */ + RT_ASSERT(intf_desc != RT_NULL); + RT_ASSERT(num < intf_desc->bNumEndpoints); + *ep_desc = RT_NULL; + + ptr = (rt_uint32_t)intf_desc + intf_desc->bLength; + while(count < intf_desc->bNumEndpoints) + { + if(depth++ > 0x20) + { + *ep_desc = RT_NULL; + return -RT_EIO; + } + desc = (udesc_t)ptr; + if(desc->type == USB_DESC_TYPE_ENDPOINT) + { + if(num == count) + { + *ep_desc = (uep_desc_t)desc; + + RT_DEBUG_LOG(RT_DEBUG_USB, + ("rt_usb_get_endpoint_descriptor: %d\n", num)); + return RT_EOK; + } + else count++; + } + ptr = (rt_uint32_t)desc + desc->bLength; + } + + rt_kprintf("rt_usb_get_endpoint_descriptor %d failed\n", num); + return -RT_EIO; +} + +int rt_usb_hcd_pipe_xfer(uhcd_t hcd, upipe_t pipe, void* buffer, int nbytes, int timeout) +{ + rt_size_t remain_size; + rt_size_t send_size; + remain_size = nbytes; + rt_uint8_t * pbuffer = (rt_uint8_t *)buffer; + do + { + RT_DEBUG_LOG(RT_DEBUG_USB,("pipe transform remain size,: %d\n", remain_size)); + send_size = (remain_size > pipe->ep.wMaxPacketSize) ? pipe->ep.wMaxPacketSize : remain_size; + if(hcd->ops->pipe_xfer(pipe, USBH_PID_DATA, pbuffer, send_size, timeout) == send_size) + { + remain_size -= send_size; + pbuffer += send_size; + } + else + { + return 0; + } + }while(remain_size > 0); + return nbytes; +} -- cgit v1.3.1