添加rtthread相关代码
This commit is contained in:
		
							
								
								
									
										34
									
								
								riscv/rtthread/components/drivers/usb/usbhost/SConscript
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										34
									
								
								riscv/rtthread/components/drivers/usb/usbhost/SConscript
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| Import('RTT_ROOT') | ||||
| from building import * | ||||
|  | ||||
| cwd = GetCurrentDir() | ||||
| src = Split(""" | ||||
| core/usbhost_core.c | ||||
| core/driver.c | ||||
| core/usbhost.c | ||||
| core/hub.c | ||||
| """) | ||||
|  | ||||
| if GetDepend('RT_USBH_ADK'): | ||||
|     src += Glob('class/adk.c') | ||||
|     src += Glob('class/adkapp.c') | ||||
|  | ||||
| if GetDepend('RT_USBH_MSTORAGE'): | ||||
|     src += Glob('class/mass.c') | ||||
|     src += Glob('class/udisk.c') | ||||
|  | ||||
| if GetDepend('RT_USBH_HID'): | ||||
|     src += Glob('class/hid.c') | ||||
|  | ||||
| if GetDepend('RT_USBH_HID_MOUSE'): | ||||
|     src += Glob('class/umouse.c') | ||||
|  | ||||
| if GetDepend('RT_USBH_HID_KEYBOARD'): | ||||
|     src += Glob('class/ukbd.c') | ||||
|  | ||||
| CPPPATH = [cwd, cwd + '/class', cwd + '/core', \ | ||||
|     cwd + '/include', cwd + '../../../include'] | ||||
|  | ||||
| group = DefineGroup('rt_usbh', src, depend = ['RT_USING_USB_HOST'], CPPPATH = CPPPATH) | ||||
|  | ||||
| Return('group') | ||||
							
								
								
									
										426
									
								
								riscv/rtthread/components/drivers/usb/usbhost/class/adk.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										426
									
								
								riscv/rtthread/components/drivers/usb/usbhost/class/adk.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,426 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2023, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2011-12-12     Yi Qiu      first version | ||||
|  */ | ||||
|  | ||||
| #include <rtthread.h> | ||||
| #include <drivers/usb_host.h> | ||||
| #include "adk.h" | ||||
|  | ||||
| #ifdef RT_USBH_ADK | ||||
|  | ||||
| #define DBG_TAG           "usbhost.adk" | ||||
| #define DBG_LVL           DBG_INFO | ||||
| #include <rtdbg.h> | ||||
|  | ||||
| static struct uclass_driver adk_driver; | ||||
| static const char* _adk_manufacturer = RT_NULL; | ||||
| static const char* _adk_model = RT_NULL; | ||||
| static const char* _adk_description = RT_NULL; | ||||
| static const char* _adk_version = RT_NULL; | ||||
| static const char* _adk_uri = RT_NULL; | ||||
| static const char* _adk_serial = RT_NULL; | ||||
|  | ||||
| rt_err_t rt_usbh_adk_set_string(const char* manufacturer, const char* model, | ||||
|     const char* description, const char* _version, const char* uri, | ||||
|     const char* serial) | ||||
| { | ||||
|     _adk_manufacturer = manufacturer; | ||||
|     _adk_model = model; | ||||
|     _adk_description = description; | ||||
|     _adk_version = _version; | ||||
|     _adk_uri = uri; | ||||
|     _adk_serial = serial; | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| #ifdef RT_USING_MODULE | ||||
| #include <rtm.h> | ||||
|  | ||||
| RTM_EXPORT(rt_usbh_adk_set_string); | ||||
| #endif | ||||
|  | ||||
| /** | ||||
|  * This function will do USB_REQ_GET_PROTOCOL request to set idle period to the usb adk device | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @duration the idle period of requesting data. | ||||
|  * @report_id the report id | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
| */ | ||||
| static rt_err_t rt_usbh_adk_get_protocol(struct uintf* intf, rt_uint16_t *protocol) | ||||
| { | ||||
|     struct urequest setup; | ||||
|     uinst_t device; | ||||
|     int timeout = USB_TIMEOUT_BASIC; | ||||
|  | ||||
|         /* parameter check */ | ||||
|     RT_ASSERT(intf != RT_NULL); | ||||
|     RT_ASSERT(intf->device != RT_NULL); | ||||
|  | ||||
|     device = intf->device; | ||||
|  | ||||
|     setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_VENDOR | | ||||
|         USB_REQ_TYPE_DEVICE; | ||||
|     setup.request = USB_REQ_GET_PROTOCOL; | ||||
|     setup.index = 0; | ||||
|     setup.length = 2; | ||||
|     setup.value = 0; | ||||
|  | ||||
|     if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, (void*)protocol, 2, | ||||
|         timeout) == 0) return RT_EOK; | ||||
|     else return -RT_FALSE; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will do USB_REQ_SEND_STRING request to set idle period to the usb adk device | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @duration the idle period of requesting data. | ||||
|  * @report_id the report id | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
| */ | ||||
| static rt_err_t rt_usbh_adk_send_string(struct uintf* intf, rt_uint16_t index, | ||||
|     const char* str) | ||||
| { | ||||
|     struct urequest setup; | ||||
|     uinst_t device; | ||||
|     int timeout = USB_TIMEOUT_BASIC; | ||||
|  | ||||
|         /* parameter check */ | ||||
|     RT_ASSERT(intf != RT_NULL); | ||||
|     RT_ASSERT(intf->device != RT_NULL); | ||||
|  | ||||
|     device = intf->device; | ||||
|  | ||||
|     setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_VENDOR | | ||||
|         USB_REQ_TYPE_DEVICE; | ||||
|     setup.request = USB_REQ_SEND_STRING; | ||||
|     setup.index = index; | ||||
|     setup.length = rt_strlen(str) + 1; | ||||
|     setup.value = 0; | ||||
|  | ||||
|     if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, (void*)str, | ||||
|         rt_strlen(str) + 1, timeout) == 0) return RT_EOK; | ||||
|     else return -RT_FALSE; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will do USB_REQ_START request to set idle period to the usb adk device | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @duration the idle period of requesting data. | ||||
|  * @report_id the report id | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
| */ | ||||
| static rt_err_t rt_usbh_adk_start(struct uintf* intf) | ||||
| { | ||||
|     struct urequest setup; | ||||
|     uinst_t device; | ||||
|     int timeout = USB_TIMEOUT_BASIC; | ||||
|  | ||||
|         /* parameter check */ | ||||
|     RT_ASSERT(intf != RT_NULL); | ||||
|     RT_ASSERT(intf->device != RT_NULL); | ||||
|  | ||||
|     device = intf->device; | ||||
|  | ||||
|     setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_VENDOR | | ||||
|         USB_REQ_TYPE_DEVICE; | ||||
|     setup.request = USB_REQ_START; | ||||
|     setup.index = 0; | ||||
|     setup.length = 0; | ||||
|     setup.value = 0; | ||||
|  | ||||
|     if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, RT_NULL, 0, | ||||
|         timeout) == 0) return RT_EOK; | ||||
|     else return -RT_FALSE; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will read data from usb adk device | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
| */ | ||||
| static rt_ssize_t rt_usbh_adk_read(rt_device_t device, rt_off_t pos, void* buffer, | ||||
|     rt_size_t size) | ||||
| { | ||||
|     uadk_t adk; | ||||
|     rt_size_t length; | ||||
|     struct uintf* intf; | ||||
|  | ||||
|     /* check parameter */ | ||||
|     RT_ASSERT(device != RT_NULL); | ||||
|     RT_ASSERT(buffer != RT_NULL); | ||||
|  | ||||
|     intf = (struct uintf*)device->user_data; | ||||
|     adk = (uadk_t)intf->user_data; | ||||
|  | ||||
|     length = rt_usb_hcd_bulk_xfer(intf->device->hcd, adk->pipe_in, | ||||
|         buffer, size, 300); | ||||
|  | ||||
|     return length; | ||||
|  | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will write data to usb adk device | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
| */ | ||||
| static rt_ssize_t rt_usbh_adk_write (rt_device_t device, rt_off_t pos, const void* buffer, | ||||
|     rt_size_t size) | ||||
| { | ||||
|     uadk_t adk; | ||||
|     rt_size_t length; | ||||
|     struct uintf* intf; | ||||
|  | ||||
|     RT_ASSERT(buffer != RT_NULL); | ||||
|  | ||||
|     intf = (struct uintf*)device->user_data; | ||||
|     adk = (uadk_t)intf->user_data; | ||||
|  | ||||
|     length = rt_usb_hcd_bulk_xfer(intf->device->hcd, adk->pipe_out, | ||||
|         (void*)buffer, size, 300); | ||||
|  | ||||
|     return length; | ||||
| } | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
| const static struct rt_device_ops adk_device_ops = | ||||
| { | ||||
|     RT_NULL; | ||||
|     RT_NULL; | ||||
|     RT_NULL; | ||||
|     rt_usbh_adk_read; | ||||
|     rt_usbh_adk_write; | ||||
|     RT_NULL; | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| /** | ||||
|  * This function will run adk class driver when usb device is detected and identified | ||||
|  *  as a adk class device, it will continue the enumulate process. | ||||
|  * | ||||
|  * @param arg the argument. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| static rt_err_t rt_usbh_adk_enable(void* arg) | ||||
| { | ||||
|     int i = 0; | ||||
|     uadk_t adk; | ||||
|     struct uintf* intf = (struct uintf*)arg; | ||||
|     udev_desc_t dev_desc; | ||||
|     rt_uint16_t protocol; | ||||
|     rt_err_t ret; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     if(intf == RT_NULL) | ||||
|     { | ||||
|         rt_kprintf("the interface is not available\n"); | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     LOG_D("rt_usbh_adk_run"); | ||||
|  | ||||
|     dev_desc = &intf->device->dev_desc; | ||||
|     if(dev_desc->idVendor == USB_ACCESSORY_VENDOR_ID && | ||||
|         (dev_desc->idProduct == USB_ACCESSORY_PRODUCT_ID || | ||||
|         dev_desc->idProduct == USB_ACCESSORY_ADB_PRODUCT_ID)) | ||||
|     { | ||||
|         if(intf->intf_desc->bInterfaceSubClass != 0xFF) return -RT_ERROR; | ||||
|  | ||||
|         LOG_D("found android accessory device"); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         LOG_D("switch device"); | ||||
|  | ||||
|         if((ret = rt_usbh_adk_get_protocol(intf, &protocol)) != RT_EOK) | ||||
|         { | ||||
|             rt_kprintf("rt_usbh_adk_get_protocol failed\n"); | ||||
|             return ret; | ||||
|         } | ||||
|  | ||||
|         if(protocol != 1) | ||||
|         { | ||||
|             rt_kprintf("read protocol failed\n"); | ||||
|             return -RT_ERROR; | ||||
|         } | ||||
|  | ||||
|         rt_usbh_adk_send_string(intf, | ||||
|             ACCESSORY_STRING_MANUFACTURER, _adk_manufacturer); | ||||
|         rt_usbh_adk_send_string(intf, | ||||
|             ACCESSORY_STRING_MODEL, _adk_model); | ||||
|         rt_usbh_adk_send_string(intf, | ||||
|             ACCESSORY_STRING_DESCRIPTION, _adk_description); | ||||
|         rt_usbh_adk_send_string(intf, | ||||
|             ACCESSORY_STRING_VERSION, _adk_version); | ||||
|         rt_usbh_adk_send_string(intf, | ||||
|             ACCESSORY_STRING_URI, _adk_uri); | ||||
|         rt_usbh_adk_send_string(intf, | ||||
|             ACCESSORY_STRING_SERIAL, _adk_serial); | ||||
|  | ||||
|         LOG_D("manufacturer %s", _adk_manufacturer); | ||||
|         LOG_D("model %s", _adk_model); | ||||
|         LOG_D("description %s", _adk_description); | ||||
|         LOG_D("version %s", _adk_version); | ||||
|         LOG_D("uri %s", _adk_uri); | ||||
|         LOG_D("serial %s", _adk_serial); | ||||
|  | ||||
|         if((ret = rt_usbh_adk_start(intf)) != RT_EOK) | ||||
|         { | ||||
|             rt_kprintf("rt_usbh_adk_start failed\n"); | ||||
|             return ret; | ||||
|         } | ||||
|  | ||||
|         return RT_EOK; | ||||
|     } | ||||
|  | ||||
|     adk = rt_malloc(sizeof(struct uadkinst)); | ||||
|     RT_ASSERT(adk != RT_NULL); | ||||
|  | ||||
|     /* initilize the data structure */ | ||||
|     rt_memset(adk, 0, sizeof(struct uadkinst)); | ||||
|     intf->user_data = (void*)adk; | ||||
|  | ||||
|     for(i=0; i<intf->intf_desc->bNumEndpoints; i++) | ||||
|     { | ||||
|         uep_desc_t ep_desc; | ||||
|  | ||||
|         /* get endpoint descriptor from interface descriptor */ | ||||
|         rt_usbh_get_endpoint_descriptor(intf->intf_desc, i, &ep_desc); | ||||
|         if(ep_desc == RT_NULL) | ||||
|         { | ||||
|             rt_kprintf("rt_usb_get_endpoint_descriptor error\n"); | ||||
|             return -RT_ERROR; | ||||
|         } | ||||
|  | ||||
|         /* the endpoint type of adk class should be BULK */ | ||||
|         if((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK) | ||||
|             continue; | ||||
|  | ||||
|         /* allocate pipes according to the endpoint type */ | ||||
|         if(ep_desc->bEndpointAddress & USB_DIR_IN) | ||||
|         { | ||||
|             /* allocate an in pipe for the adk instance */ | ||||
|             ret = rt_usb_hcd_alloc_pipe(intf->device->hcd, &adk->pipe_in, | ||||
|                 intf, ep_desc, RT_NULL); | ||||
|             if(ret != RT_EOK) return ret; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             /* allocate an output pipe for the adk instance */ | ||||
|             ret = rt_usb_hcd_alloc_pipe(intf->device->hcd, &adk->pipe_out, | ||||
|                 intf, ep_desc, RT_NULL); | ||||
|             if(ret != RT_EOK) return ret; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* check pipes infomation */ | ||||
|     if(adk->pipe_in == RT_NULL || adk->pipe_out == RT_NULL) | ||||
|     { | ||||
|         rt_kprintf("pipe error, unsupported device\n"); | ||||
|         return -RT_ERROR; | ||||
|     } | ||||
|  | ||||
|     /* set configuration */ | ||||
|     ret = rt_usbh_set_configure(intf->device, 1); | ||||
|     if(ret != RT_EOK) return ret; | ||||
|  | ||||
|     /* register adk device */ | ||||
|     adk->device.type    = RT_Device_Class_Char; | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
|     adk->device.ops     = &adk_device_ops; | ||||
| #else | ||||
|     adk->device.init    = RT_NULL; | ||||
|     adk->device.open    = RT_NULL; | ||||
|     adk->device.close   = RT_NULL; | ||||
|     adk->device.read    = rt_usbh_adk_read; | ||||
|     adk->device.write   = rt_usbh_adk_write; | ||||
|     adk->device.control = RT_NULL; | ||||
| #endif | ||||
|     adk->device.user_data = (void*)intf; | ||||
|  | ||||
|     rt_device_register(&adk->device, "adkdev", RT_DEVICE_FLAG_RDWR); | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will be invoked when usb device plug out is detected and it would clean | ||||
|  * and release all hub class related resources. | ||||
|  * | ||||
|  * @param arg the argument. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| static rt_err_t rt_usbh_adk_disable(void* arg) | ||||
| { | ||||
|     uadk_t adk; | ||||
|     struct uintf* intf = (struct uintf*)arg; | ||||
|  | ||||
|     RT_ASSERT(intf != RT_NULL); | ||||
|  | ||||
|     LOG_D("rt_usbh_adk_stop"); | ||||
|  | ||||
|     adk = (uadk_t)intf->user_data; | ||||
|     if(adk == RT_NULL) | ||||
|     { | ||||
|         rt_free(intf); | ||||
|         return RT_EOK; | ||||
|     } | ||||
|  | ||||
|     if(adk->pipe_in != RT_NULL) | ||||
|         rt_usb_hcd_free_pipe(intf->device->hcd, adk->pipe_in); | ||||
|  | ||||
|     if(adk->pipe_out != RT_NULL) | ||||
|         rt_usb_hcd_free_pipe(intf->device->hcd, adk->pipe_out); | ||||
|  | ||||
|     /* unregister adk device */ | ||||
|     rt_device_unregister(&adk->device); | ||||
|  | ||||
|     /* free adk instance */ | ||||
|     if(adk != RT_NULL) | ||||
|     { | ||||
|         rt_free(adk); | ||||
|     } | ||||
|  | ||||
|     /* free interface instance */ | ||||
|     rt_free(intf); | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will register adk class driver to the usb class driver manager. | ||||
|  * and it should be invoked in the usb system initialization. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| ucd_t rt_usbh_class_driver_adk(void) | ||||
| { | ||||
|     adk_driver.class_code = USB_CLASS_ADK; | ||||
|  | ||||
|     adk_driver.enable = rt_usbh_adk_enable; | ||||
|     adk_driver.disable = rt_usbh_adk_disable; | ||||
|  | ||||
|     return &adk_driver; | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										43
									
								
								riscv/rtthread/components/drivers/usb/usbhost/class/adk.h
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										43
									
								
								riscv/rtthread/components/drivers/usb/usbhost/class/adk.h
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2023, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2011-12-12     Yi Qiu      first version | ||||
|  */ | ||||
|  | ||||
| #ifndef __ADK_H__ | ||||
| #define __ADK_H__ | ||||
|  | ||||
| #include <rtthread.h> | ||||
|  | ||||
| struct uadkinst | ||||
| { | ||||
|     upipe_t pipe_in; | ||||
|     upipe_t pipe_out; | ||||
|  | ||||
|     struct rt_device device; | ||||
| }; | ||||
| typedef struct uadkinst* uadk_t; | ||||
|  | ||||
| #define USB_ACCESSORY_VENDOR_ID         0x18D1 | ||||
| #define USB_ACCESSORY_PRODUCT_ID        0x2D00 | ||||
| #define USB_ACCESSORY_ADB_PRODUCT_ID    0x2D01 | ||||
|  | ||||
| #define ACCESSORY_STRING_MANUFACTURER   0 | ||||
| #define ACCESSORY_STRING_MODEL          1 | ||||
| #define ACCESSORY_STRING_DESCRIPTION    2 | ||||
| #define ACCESSORY_STRING_VERSION        3 | ||||
| #define ACCESSORY_STRING_URI            4 | ||||
| #define ACCESSORY_STRING_SERIAL         5 | ||||
|  | ||||
| #define USB_REQ_GET_PROTOCOL            51 | ||||
| #define USB_REQ_SEND_STRING             52 | ||||
| #define USB_REQ_START                   53 | ||||
|  | ||||
| #define USB_CLASS_ADK                   0xff | ||||
|  | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										410
									
								
								riscv/rtthread/components/drivers/usb/usbhost/class/hid.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										410
									
								
								riscv/rtthread/components/drivers/usb/usbhost/class/hid.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,410 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2023, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2011-12-12     Yi Qiu      first version | ||||
|  * 2021-02-23     Leslie Lee  update with current usb api | ||||
|  */ | ||||
|  | ||||
| #include <rtthread.h> | ||||
| #include <drivers/usb_host.h> | ||||
| #include "hid.h" | ||||
|  | ||||
| #ifdef RT_USBH_HID | ||||
|  | ||||
| #define DBG_TAG           "usbhost.hid" | ||||
| #define DBG_LVL           DBG_INFO | ||||
| #include <rtdbg.h> | ||||
|  | ||||
| static struct uclass_driver hid_driver; | ||||
| static rt_list_t _protocal_list; | ||||
|  | ||||
| /** | ||||
|  * This function will do USB_REQ_SET_IDLE request to set idle period to the usb hid device | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @duration the idle period of requesting data. | ||||
|  * @report_id the report id | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
| */ | ||||
| rt_err_t rt_usbh_hid_set_idle(struct uhintf* intf, int duration, int report_id) | ||||
| { | ||||
|     struct urequest setup; | ||||
|     struct uinstance* device; | ||||
|     int timeout = USB_TIMEOUT_BASIC; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(intf != RT_NULL); | ||||
|     RT_ASSERT(intf->device != RT_NULL); | ||||
|  | ||||
|     device = intf->device; | ||||
|  | ||||
|     setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS | | ||||
|         USB_REQ_TYPE_INTERFACE; | ||||
|     setup.bRequest = USB_REQ_SET_IDLE; | ||||
|     setup.wIndex = 0; | ||||
|     setup.wLength = 0; | ||||
|     setup.wValue = (duration << 8 )| report_id; | ||||
|  | ||||
|     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, RT_NULL, 0, timeout) == 0) | ||||
|             return RT_EOK; | ||||
|  | ||||
|     return -RT_FALSE; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will do USB_REQ_GET_REPORT request to get report from the usb hid device | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @buffer the data buffer to save usb report descriptor. | ||||
|  * @param nbytes the size of buffer | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
| */ | ||||
| rt_err_t rt_usbh_hid_get_report(struct uhintf* intf, rt_uint8_t type, | ||||
|     rt_uint8_t id, rt_uint8_t *buffer, rt_size_t size) | ||||
| { | ||||
|     struct urequest setup; | ||||
|     struct uinstance* device; | ||||
|     int timeout = USB_TIMEOUT_BASIC; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(intf != RT_NULL); | ||||
|     RT_ASSERT(intf->device != RT_NULL); | ||||
|  | ||||
|     device = intf->device; | ||||
|  | ||||
|     setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | | ||||
|         USB_REQ_TYPE_INTERFACE; | ||||
|     setup.bRequest = USB_REQ_GET_REPORT; | ||||
|     setup.wIndex = intf->intf_desc->bInterfaceNumber; | ||||
|     setup.wLength = size; | ||||
|     setup.wValue = (type << 8 ) + id; | ||||
|  | ||||
|     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, size, timeout) == size) | ||||
|         { | ||||
|             if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) == 0) | ||||
|             { | ||||
|                 return RT_EOK; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|         return -RT_FALSE; | ||||
|     return -RT_FALSE; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will do USB_REQ_SET_REPORT request to set report to the usb hid device | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @buffer the data buffer to save usb report descriptor. | ||||
|  * @param nbytes the size of buffer | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
| */ | ||||
| rt_err_t rt_usbh_hid_set_report(struct uhintf* intf, rt_uint8_t *buffer, rt_size_t size) | ||||
| { | ||||
|     struct urequest setup; | ||||
|     struct uinstance* device; | ||||
|     int timeout = USB_TIMEOUT_BASIC; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(intf != RT_NULL); | ||||
|     RT_ASSERT(intf->device != RT_NULL); | ||||
|  | ||||
|     device = intf->device; | ||||
|  | ||||
|     setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS | | ||||
|         USB_REQ_TYPE_INTERFACE; | ||||
|     setup.bRequest = USB_REQ_SET_REPORT; | ||||
|     setup.wIndex = intf->intf_desc->bInterfaceNumber; | ||||
|     setup.wLength = size; | ||||
|     setup.wValue = 0x02 << 8; | ||||
|  | ||||
|     if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8) | ||||
|         return RT_EOK; | ||||
|     else | ||||
|         return -RT_FALSE; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will do USB_REQ_SET_PROTOCOL request to set protocal to the usb hid device. | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @param protocol the protocol id. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_hid_set_protocal(struct uhintf* intf, int protocol) | ||||
| { | ||||
|     struct urequest setup; | ||||
|     struct uinstance* device; | ||||
|     int timeout = USB_TIMEOUT_BASIC; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(intf != RT_NULL); | ||||
|     RT_ASSERT(intf->device != RT_NULL); | ||||
|  | ||||
|     device = intf->device; | ||||
|  | ||||
|     setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS | | ||||
|         USB_REQ_TYPE_INTERFACE; | ||||
|     setup.bRequest = USB_REQ_SET_PROTOCOL; | ||||
|     setup.wIndex = 0; | ||||
|     setup.wLength = 0; | ||||
|     setup.wValue = protocol; | ||||
|  | ||||
|     if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8) | ||||
|         return RT_EOK; | ||||
|     else | ||||
|         return -RT_FALSE; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will do USB_REQ_GET_DESCRIPTOR request for the device instance | ||||
|  * to set feature of the hub port. | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @buffer the data buffer to save usb report descriptor. | ||||
|  * @param nbytes the size of buffer | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_hid_get_report_descriptor(struct uhintf* intf, | ||||
|     rt_uint8_t *buffer, rt_size_t size) | ||||
| { | ||||
|     struct urequest setup; | ||||
|     struct uinstance* device; | ||||
|     int timeout = USB_TIMEOUT_BASIC; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(intf != RT_NULL); | ||||
|     RT_ASSERT(intf->device != RT_NULL); | ||||
|  | ||||
|     device = intf->device; | ||||
|  | ||||
|     setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_STANDARD| | ||||
|         USB_REQ_TYPE_INTERFACE; | ||||
|     setup.bRequest = USB_REQ_GET_DESCRIPTOR; | ||||
|     setup.wIndex = 0; | ||||
|     setup.wLength = size; | ||||
|     setup.wValue = USB_DESC_TYPE_REPORT << 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, size, timeout) == size) | ||||
|         { | ||||
|             if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) == 0) | ||||
|             { | ||||
|                 return RT_EOK; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|         return -RT_FALSE; | ||||
|     return -RT_FALSE; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will register specified hid protocal to protocal list | ||||
|  * | ||||
|  * @param protocal the specified protocal. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_hid_protocal_register(uprotocal_t protocal) | ||||
| { | ||||
|     RT_ASSERT(protocal != RT_NULL); | ||||
|  | ||||
|     if (protocal == RT_NULL) return -RT_ERROR; | ||||
|  | ||||
|     /* insert class driver into driver list */ | ||||
|     rt_list_insert_after(&_protocal_list, &(protocal->list)); | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function is the callback function of hid's int endpoint, it is invoked when data comes. | ||||
|  * | ||||
|  * @param context the context of the callback function. | ||||
|  * | ||||
|  * @return none. | ||||
|  */ | ||||
| static void rt_usbh_hid_callback(void* context) | ||||
| { | ||||
|     upipe_t pipe; | ||||
|     struct uhid* hid; | ||||
|     int timeout = USB_TIMEOUT_LONG; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(context != RT_NULL); | ||||
|  | ||||
|     pipe = (upipe_t)context; | ||||
|     hid = (struct uhid*)((struct uhintf*)pipe->inst)->user_data; | ||||
|  | ||||
|     /* invoke protocal callback function */ | ||||
|     hid->protocal->callback((void*)hid); | ||||
|  | ||||
|     /* parameter check */ | ||||
|      RT_ASSERT(((struct uhintf*)pipe->inst)->device->hcd != RT_NULL); | ||||
|  | ||||
|     rt_usb_hcd_pipe_xfer(((struct uhintf*)pipe->inst)->device->hcd, pipe, | ||||
|         hid->buffer, pipe->ep.wMaxPacketSize, timeout); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will find specified hid protocal from protocal list | ||||
|  * | ||||
|  * @param pro_id the protocal id. | ||||
|  * | ||||
|  * @return the found protocal or RT_NULL if there is no this protocal. | ||||
|  */ | ||||
| static uprotocal_t rt_usbh_hid_protocal_find(int pro_id) | ||||
| { | ||||
|     struct rt_list_node *node; | ||||
|  | ||||
|     /* try to find protocal object */ | ||||
|     for (node = _protocal_list.next; node != &_protocal_list; node = node->next) | ||||
|     { | ||||
|         uprotocal_t protocal = | ||||
|             (uprotocal_t)rt_list_entry(node, struct uprotocal, list); | ||||
|         if (protocal->pro_id == pro_id) return protocal; | ||||
|     } | ||||
|  | ||||
|     /* not found */ | ||||
|     return RT_NULL; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will run hid class driver when usb device is detected and identified | ||||
|  *  as a hid class device, it will continue the enumulate process. | ||||
|  * | ||||
|  * @param arg the argument. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| static rt_err_t rt_usbh_hid_enable(void* arg) | ||||
| { | ||||
|     int i = 0, pro_id; | ||||
|     uprotocal_t protocal; | ||||
|     struct uhid* hid; | ||||
|     struct uhintf* intf = (struct uhintf*)arg; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     if(intf == RT_NULL) | ||||
|     { | ||||
|         rt_kprintf("the interface is not available\n"); | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     pro_id = intf->intf_desc->bInterfaceProtocol; | ||||
|  | ||||
|     LOG_D("HID device enable, protocal id %d", pro_id); | ||||
|  | ||||
|     protocal = rt_usbh_hid_protocal_find(pro_id); | ||||
|     if(protocal == RT_NULL) | ||||
|     { | ||||
|         rt_kprintf("can't find hid protocal %d\n", pro_id); | ||||
|         intf->user_data = RT_NULL; | ||||
|         return -RT_ERROR; | ||||
|     } | ||||
|  | ||||
|     hid = rt_malloc(sizeof(struct uhid)); | ||||
|     RT_ASSERT(hid != RT_NULL); | ||||
|  | ||||
|     /* initilize the data structure */ | ||||
|     rt_memset(hid, 0, sizeof(struct uhid)); | ||||
|     intf->user_data = (void*)hid; | ||||
|     hid->protocal = protocal; | ||||
|  | ||||
|     for(i=0; i<intf->intf_desc->bNumEndpoints; i++) | ||||
|     { | ||||
|         rt_err_t ret; | ||||
|         uep_desc_t ep_desc; | ||||
|  | ||||
|         /* get endpoint descriptor */ | ||||
|         rt_usbh_get_endpoint_descriptor(intf->intf_desc, i, &ep_desc); | ||||
|         if(ep_desc == RT_NULL) | ||||
|         { | ||||
|             rt_kprintf("rt_usbh_get_endpoint_descriptor error\n"); | ||||
|             return -RT_ERROR; | ||||
|         } | ||||
|  | ||||
|         if(USB_EP_ATTR(ep_desc->bmAttributes) != USB_EP_ATTR_INT) | ||||
|             continue; | ||||
|  | ||||
|         if(!(ep_desc->bEndpointAddress & USB_DIR_IN)) continue; | ||||
|  | ||||
|         ret = rt_usb_hcd_alloc_pipe(intf->device->hcd, &hid->pipe_in, | ||||
|             intf->device, ep_desc); | ||||
|         if(ret != RT_EOK) return ret; | ||||
|     } | ||||
|  | ||||
|     /* initialize hid protocal */ | ||||
|     hid->protocal->init((void*)intf); | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will be invoked when usb device plug out is detected and it would clean | ||||
|  * and release all hub class related resources. | ||||
|  * | ||||
|  * @param arg the argument. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| static rt_err_t rt_usbh_hid_disable(void* arg) | ||||
| { | ||||
|     struct uhid* hid; | ||||
|     struct uhintf* intf = (struct uhintf*)arg; | ||||
|  | ||||
|     RT_ASSERT(intf != RT_NULL); | ||||
|  | ||||
|     LOG_D("rt_usbh_hid_disable"); | ||||
|  | ||||
|     hid = (struct uhid*)intf->user_data; | ||||
|     if(hid != RT_NULL) | ||||
|     { | ||||
|         if(hid->pipe_in != RT_NULL) | ||||
|         { | ||||
|             /* free the HID in pipe */ | ||||
|             rt_usb_hcd_free_pipe(intf->device->hcd, hid->pipe_in); | ||||
|         } | ||||
|  | ||||
|         /* free the hid instance */ | ||||
|         rt_free(hid); | ||||
|     } | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will register hid class driver to the usb class driver manager. | ||||
|  * and it should be invoked in the usb system initialization. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| ucd_t rt_usbh_class_driver_hid(void) | ||||
| { | ||||
|     rt_list_init(&_protocal_list); | ||||
|  | ||||
|     hid_driver.class_code = USB_CLASS_HID; | ||||
|  | ||||
|     hid_driver.enable = rt_usbh_hid_enable; | ||||
|     hid_driver.disable = rt_usbh_hid_disable; | ||||
|  | ||||
|     return &hid_driver; | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										41
									
								
								riscv/rtthread/components/drivers/usb/usbhost/class/hid.h
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										41
									
								
								riscv/rtthread/components/drivers/usb/usbhost/class/hid.h
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2023, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2011-12-12     Yi Qiu      first version | ||||
|  */ | ||||
|  | ||||
| #ifndef __HID_H__ | ||||
| #define __HID_H__ | ||||
|  | ||||
| #include <rtthread.h> | ||||
|  | ||||
| struct uhid | ||||
| { | ||||
|     upipe_t pipe_in; | ||||
|     rt_uint8_t buffer[8]; | ||||
|     uprotocal_t protocal; | ||||
| }; | ||||
| typedef struct uhid uhid_t; | ||||
|  | ||||
| #define USB_REQ_GET_REPORT      0x01 | ||||
| #define USB_REQ_GET_IDLE        0x02 | ||||
| #define USB_REQ_GET_PROTOCOL    0x03 | ||||
| #define USB_REQ_SET_REPORT      0x09 | ||||
| #define USB_REQ_SET_IDLE        0x0a | ||||
| #define USB_REQ_SET_PROTOCOL    0x0b | ||||
|  | ||||
| #define USB_HID_KEYBOARD        1 | ||||
| #define USB_HID_MOUSE            2 | ||||
|  | ||||
| rt_err_t rt_usbh_hid_set_idle(struct uhintf* intf, int duration, int report_id); | ||||
| rt_err_t rt_usbh_hid_get_report(struct uhintf* intf, rt_uint8_t type, rt_uint8_t id, rt_uint8_t *buffer, rt_size_t size); | ||||
| rt_err_t rt_usbh_hid_set_report(struct uhintf* intf, rt_uint8_t *buffer, rt_size_t size); | ||||
| rt_err_t rt_usbh_hid_set_protocal(struct uhintf* intf, int protocol); | ||||
| rt_err_t rt_usbh_hid_get_report_descriptor(struct uhintf* intf, rt_uint8_t *buffer, rt_size_t size); | ||||
| rt_err_t rt_usbh_hid_protocal_register(uprotocal_t protocal); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										647
									
								
								riscv/rtthread/components/drivers/usb/usbhost/class/mass.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										647
									
								
								riscv/rtthread/components/drivers/usb/usbhost/class/mass.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,647 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2023, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2011-12-12     Yi Qiu      first version | ||||
|  */ | ||||
|  | ||||
| #include <rtthread.h> | ||||
| #include <drivers/usb_host.h> | ||||
| #include "mass.h" | ||||
|  | ||||
| #ifdef RT_USBH_MSTORAGE | ||||
|  | ||||
| #define DBG_TAG           "usbhost.mass" | ||||
| #define DBG_LVL           DBG_INFO | ||||
| #include <rtdbg.h> | ||||
|  | ||||
| extern rt_err_t rt_udisk_run(struct uhintf* intf); | ||||
| extern rt_err_t rt_udisk_stop(struct uhintf* intf); | ||||
|  | ||||
| static struct uclass_driver storage_driver; | ||||
|  | ||||
| /** | ||||
|  * This function will do USBREQ_GET_MAX_LUN request for the usb interface instance. | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @param max_lun the buffer to save max_lun. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| static rt_err_t _pipe_check(struct uhintf* intf, upipe_t pipe) | ||||
| { | ||||
|     struct uinstance* device; | ||||
|     rt_err_t ret; | ||||
|     ustor_t stor; | ||||
|     int size = 0; | ||||
|     struct ustorage_csw csw; | ||||
|  | ||||
|     if(intf == RT_NULL || pipe == RT_NULL) | ||||
|     { | ||||
|         rt_kprintf("the interface is not available\n"); | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     /* get usb device instance from the interface instance */ | ||||
|     device = intf->device; | ||||
|  | ||||
|     /* get storage instance from the interface instance */ | ||||
|     stor = (ustor_t)intf->user_data; | ||||
|  | ||||
|     /* check pipe status */ | ||||
|     if(pipe->status == UPIPE_STATUS_OK) return RT_EOK; | ||||
|  | ||||
|     if(pipe->status == UPIPE_STATUS_ERROR) | ||||
|     { | ||||
|         rt_kprintf("pipe status error\n"); | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|     if(pipe->status == UPIPE_STATUS_STALL) | ||||
|     { | ||||
|         /* clear the pipe stall status */ | ||||
|         ret = rt_usbh_clear_feature(device, pipe->ep.bEndpointAddress, | ||||
|             USB_FEATURE_ENDPOINT_HALT); | ||||
|         if(ret != RT_EOK) return ret; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     rt_thread_delay(50); | ||||
|  | ||||
|     rt_kprintf("pipes1 0x%x, 0x%x\n", stor->pipe_in, stor->pipe_out); | ||||
|  | ||||
|     stor->pipe_in->status = UPIPE_STATUS_OK; | ||||
|  | ||||
|     LOG_D("clean storage in pipe stall"); | ||||
|  | ||||
|     /* it should receive csw after clear the stall feature */ | ||||
|     size = rt_usb_hcd_pipe_xfer(stor->pipe_in->inst->hcd, | ||||
|         stor->pipe_in, &csw, SIZEOF_CSW, 100); | ||||
|     if(size != SIZEOF_CSW) | ||||
|     { | ||||
|         rt_kprintf("receive the csw after stall failed\n"); | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     return -RT_ERROR; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will do USBREQ_GET_MAX_LUN request for the usb interface instance. | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @param max_lun the buffer to save max_lun. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| static rt_err_t rt_usb_bulk_only_xfer(struct uhintf* intf, | ||||
|     ustorage_cbw_t cmd, rt_uint8_t* buffer, int timeout) | ||||
| { | ||||
|     rt_size_t size; | ||||
|     rt_err_t ret; | ||||
|     upipe_t pipe; | ||||
|     struct ustorage_csw csw; | ||||
|     ustor_t stor; | ||||
|  | ||||
|     RT_ASSERT(cmd != RT_NULL); | ||||
|  | ||||
|     if(intf == RT_NULL) | ||||
|     { | ||||
|         rt_kprintf("the interface is not available\n"); | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     /* get storage instance from the interface instance */ | ||||
|     stor = (ustor_t)intf->user_data; | ||||
|  | ||||
|     do | ||||
|     { | ||||
|         /* send the cbw */ | ||||
|         size = rt_usb_hcd_pipe_xfer(stor->pipe_out->inst->hcd, stor->pipe_out, | ||||
|             cmd, SIZEOF_CBW, timeout); | ||||
|         if(size != SIZEOF_CBW) | ||||
|         { | ||||
|             rt_kprintf("CBW size error\n"); | ||||
|             return -RT_EIO; | ||||
|         } | ||||
|         if(cmd->xfer_len != 0) | ||||
|         { | ||||
|             pipe = (cmd->dflags == CBWFLAGS_DIR_IN) ? stor->pipe_in : | ||||
|                 stor->pipe_out; | ||||
|             size = rt_usb_hcd_pipe_xfer(pipe->inst->hcd, pipe, (void*)buffer, | ||||
|                 cmd->xfer_len, timeout); | ||||
|             if(size != cmd->xfer_len) | ||||
|             { | ||||
|                 rt_kprintf("request size %d, transfer size %d\n", | ||||
|                     cmd->xfer_len, size); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /* receive the csw */ | ||||
|         size = rt_usb_hcd_pipe_xfer(stor->pipe_in->inst->hcd, stor->pipe_in, | ||||
|             &csw, SIZEOF_CSW, timeout); | ||||
|         if(size != SIZEOF_CSW) | ||||
|         { | ||||
|             rt_kprintf("csw size error\n"); | ||||
|             return -RT_EIO; | ||||
|         } | ||||
|     }while(0); | ||||
|  | ||||
|     /* check in pipes status */ | ||||
|     ret = _pipe_check(intf, stor->pipe_in); | ||||
|     if(ret != RT_EOK) | ||||
|     { | ||||
|         rt_kprintf("in pipe error\n"); | ||||
|         return ret; | ||||
|     } | ||||
|  | ||||
|     /* check out pipes status */ | ||||
|     ret = _pipe_check(intf, stor->pipe_out); | ||||
|     if(ret != RT_EOK) | ||||
|     { | ||||
|         rt_kprintf("out pipe error\n"); | ||||
|         return ret; | ||||
|     } | ||||
|  | ||||
|     /* check csw status */ | ||||
|     if(csw.signature != CSW_SIGNATURE || csw.tag != CBW_TAG_VALUE) | ||||
|     { | ||||
|         rt_kprintf("csw signature error\n"); | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     if(csw.status != 0) | ||||
|     { | ||||
|         //rt_kprintf("csw status error:%d\n",csw.status); | ||||
|         return -RT_ERROR; | ||||
|     } | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will do USBREQ_GET_MAX_LUN request for the usb interface instance. | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @param max_lun the buffer to save max_lun. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_storage_get_max_lun(struct uhintf* intf, rt_uint8_t* max_lun) | ||||
| { | ||||
|     struct uinstance* device; | ||||
|     struct urequest setup; | ||||
|     int timeout = USB_TIMEOUT_BASIC; | ||||
|  | ||||
|     if(intf == RT_NULL) | ||||
|     { | ||||
|         rt_kprintf("the interface is not available\n"); | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(intf->device != RT_NULL); | ||||
|     LOG_D("rt_usbh_storage_get_max_lun"); | ||||
|  | ||||
|     /* get usb device instance from the interface instance */ | ||||
|     device = intf->device; | ||||
|  | ||||
|     /* construct the request */ | ||||
|     setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | | ||||
|         USB_REQ_TYPE_INTERFACE; | ||||
|     setup.bRequest = USBREQ_GET_MAX_LUN; | ||||
|     setup.wValue = intf->intf_desc->bInterfaceNumber; | ||||
|     setup.wIndex = 0; | ||||
|     setup.wLength = 1; | ||||
|  | ||||
|     /* do control transfer request */ | ||||
|     if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8) | ||||
|     { | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|     if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, max_lun, 1, timeout) != 1) | ||||
|     { | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|     if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) != 0) | ||||
|     { | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will do USBREQ_MASS_STORAGE_RESET request for the usb interface instance. | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_storage_reset(struct uhintf* intf) | ||||
| { | ||||
|     struct urequest setup; | ||||
|     struct uinstance* device; | ||||
|     int timeout = USB_TIMEOUT_BASIC; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     if(intf == RT_NULL) | ||||
|     { | ||||
|         rt_kprintf("the interface is not available\n"); | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     RT_ASSERT(intf->device != RT_NULL); | ||||
|     LOG_D("rt_usbh_storage_reset"); | ||||
|  | ||||
|     /* get usb device instance from the interface instance */ | ||||
|     device = intf->device; | ||||
|  | ||||
|     /* construct the request */ | ||||
|     setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS | | ||||
|         USB_REQ_TYPE_INTERFACE; | ||||
|     setup.bRequest = USBREQ_MASS_STORAGE_RESET; | ||||
|     setup.wIndex = intf->intf_desc->bInterfaceNumber; | ||||
|     setup.wLength = 0; | ||||
|     setup.wValue = 0; | ||||
|  | ||||
|     if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8) | ||||
|     { | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|     if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) != 0) | ||||
|     { | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will execute SCSI_READ_10 command to read data from the usb device. | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @param buffer the data buffer to save read data | ||||
|  * @param sector the start sector address to read. | ||||
|  * @param sector the sector count to read. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_storage_read10(struct uhintf* intf, rt_uint8_t *buffer, | ||||
|     rt_uint32_t sector, rt_size_t count, int timeout) | ||||
| { | ||||
|     struct ustorage_cbw cmd; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     if(intf == RT_NULL) | ||||
|     { | ||||
|         rt_kprintf("interface is not available\n"); | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     RT_ASSERT(intf->device != RT_NULL); | ||||
|     LOG_D("rt_usbh_storage_read10"); | ||||
|  | ||||
|     /* construct the command block wrapper */ | ||||
|     rt_memset(&cmd, 0, sizeof(struct ustorage_cbw)); | ||||
|     cmd.signature = CBW_SIGNATURE; | ||||
|     cmd.tag = CBW_TAG_VALUE; | ||||
|     cmd.xfer_len = SECTOR_SIZE * count; | ||||
|     cmd.dflags = CBWFLAGS_DIR_IN; | ||||
|     cmd.lun = 0; | ||||
|     cmd.cb_len = 10; | ||||
|     cmd.cb[0] = SCSI_READ_10; | ||||
|     cmd.cb[1] = 0; | ||||
|     cmd.cb[2] = (rt_uint8_t)(sector >> 24); | ||||
|     cmd.cb[3] = (rt_uint8_t)(sector >> 16); | ||||
|     cmd.cb[4] = (rt_uint8_t)(sector >> 8); | ||||
|     cmd.cb[5] = (rt_uint8_t)sector; | ||||
|     cmd.cb[6] = 0; | ||||
|     cmd.cb[7] = (count & 0xff00) >> 8; | ||||
|     cmd.cb[8] = (rt_uint8_t) count & 0xff; | ||||
|  | ||||
|     return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will execute SCSI_WRITE_10 command to write data to the usb device. | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @param buffer the data buffer to save write data | ||||
|  * @param sector the start sector address to write. | ||||
|  * @param sector the sector count to write. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_storage_write10(struct uhintf* intf, rt_uint8_t *buffer, | ||||
|     rt_uint32_t sector, rt_size_t count, int timeout) | ||||
| { | ||||
|     struct ustorage_cbw cmd; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     if(intf == RT_NULL) | ||||
|     { | ||||
|         rt_kprintf("the interface is not available\n"); | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     RT_ASSERT(intf->device != RT_NULL); | ||||
|     LOG_D("rt_usbh_storage_write10"); | ||||
|  | ||||
|     /* construct the command block wrapper */ | ||||
|     rt_memset(&cmd, 0, sizeof(struct ustorage_cbw)); | ||||
|     cmd.signature = CBW_SIGNATURE; | ||||
|     cmd.tag = CBW_TAG_VALUE; | ||||
|     cmd.xfer_len = SECTOR_SIZE * count; | ||||
|     cmd.dflags = CBWFLAGS_DIR_OUT; | ||||
|     cmd.lun = 0; | ||||
|     cmd.cb_len = 10; | ||||
|     cmd.cb[0] = SCSI_WRITE_10; | ||||
|     cmd.cb[1] = 0; | ||||
|     cmd.cb[2] = (rt_uint8_t)(sector >> 24); | ||||
|     cmd.cb[3] = (rt_uint8_t)(sector >> 16); | ||||
|     cmd.cb[4] = (rt_uint8_t)(sector >> 8); | ||||
|     cmd.cb[5] = (rt_uint8_t)sector; | ||||
|     cmd.cb[6] = 0; | ||||
|     cmd.cb[7] = (count & 0xff00) >> 8; | ||||
|     cmd.cb[8] = (rt_uint8_t) count & 0xff; | ||||
|  | ||||
|     return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will execute SCSI_REQUEST_SENSE command to get sense data. | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @param buffer the data buffer to save sense data | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_storage_request_sense(struct uhintf* intf, rt_uint8_t* buffer) | ||||
| { | ||||
|     struct ustorage_cbw cmd; | ||||
|     int timeout = USB_TIMEOUT_LONG; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     if(intf == RT_NULL) | ||||
|     { | ||||
|         rt_kprintf("the interface is not available\n"); | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     RT_ASSERT(intf->device != RT_NULL); | ||||
|     LOG_D("rt_usbh_storage_request_sense"); | ||||
|  | ||||
|     /* construct the command block wrapper */ | ||||
|     rt_memset(&cmd, 0, sizeof(struct ustorage_cbw)); | ||||
|     cmd.signature = CBW_SIGNATURE; | ||||
|     cmd.tag = CBW_TAG_VALUE; | ||||
|     cmd.xfer_len = 18; | ||||
|     cmd.dflags = CBWFLAGS_DIR_IN; | ||||
|     cmd.lun = 0; | ||||
|     cmd.cb_len = 6; | ||||
|     cmd.cb[0] = SCSI_REQUEST_SENSE; | ||||
|     cmd.cb[4] = 18; | ||||
|  | ||||
|     return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will execute SCSI_TEST_UNIT_READY command to get unit ready status. | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_storage_test_unit_ready(struct uhintf* intf) | ||||
| { | ||||
|     struct ustorage_cbw cmd; | ||||
|     int timeout = USB_TIMEOUT_LONG; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     if(intf == RT_NULL) | ||||
|     { | ||||
|         rt_kprintf("the interface is not available\n"); | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     RT_ASSERT(intf->device != RT_NULL); | ||||
|     LOG_D("rt_usbh_storage_test_unit_ready"); | ||||
|  | ||||
|     /* construct the command block wrapper */ | ||||
|     rt_memset(&cmd, 0, sizeof(struct ustorage_cbw)); | ||||
|     cmd.signature = CBW_SIGNATURE; | ||||
|     cmd.tag = CBW_TAG_VALUE; | ||||
|     cmd.xfer_len = 0; | ||||
|     cmd.dflags = CBWFLAGS_DIR_OUT; | ||||
|     cmd.lun = 0; | ||||
|     cmd.cb_len = 12; | ||||
|     cmd.cb[0] = SCSI_TEST_UNIT_READY; | ||||
|  | ||||
|     return rt_usb_bulk_only_xfer(intf, &cmd, RT_NULL, timeout); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will execute SCSI_INQUIRY_CMD command to get inquiry data. | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @param buffer the data buffer to save inquiry data | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_storage_inquiry(struct uhintf* intf, rt_uint8_t* buffer) | ||||
| { | ||||
|     struct ustorage_cbw cmd; | ||||
|     int timeout = USB_TIMEOUT_LONG; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     if(intf == RT_NULL) | ||||
|     { | ||||
|         rt_kprintf("the interface is not available\n"); | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     RT_ASSERT(intf->device != RT_NULL); | ||||
|     LOG_D("rt_usbh_storage_inquiry"); | ||||
|  | ||||
|     /* construct the command block wrapper */ | ||||
|     rt_memset(&cmd, 0, sizeof(struct ustorage_cbw)); | ||||
|     cmd.signature = CBW_SIGNATURE; | ||||
|     cmd.tag = CBW_TAG_VALUE; | ||||
|     cmd.xfer_len = 36; | ||||
|     cmd.dflags = CBWFLAGS_DIR_IN; | ||||
|     cmd.lun = 0; | ||||
|     cmd.cb_len = 6;//12 | ||||
|     cmd.cb[0] = SCSI_INQUIRY_CMD; | ||||
|     cmd.cb[4] = 36; | ||||
|  | ||||
|     return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will execute SCSI_READ_CAPACITY command to get capacity data. | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @param buffer the data buffer to save capacity data | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_storage_get_capacity(struct uhintf* intf, rt_uint8_t* buffer) | ||||
| { | ||||
|     struct ustorage_cbw cmd; | ||||
|     int timeout = USB_TIMEOUT_LONG; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     if(intf == RT_NULL) | ||||
|     { | ||||
|         rt_kprintf("the interface is not available\n"); | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     RT_ASSERT(intf->device != RT_NULL); | ||||
|     LOG_D("rt_usbh_storage_get_capacity"); | ||||
|  | ||||
|     /* construct the command block wrapper */ | ||||
|     rt_memset(&cmd, 0, sizeof(struct ustorage_cbw)); | ||||
|     cmd.signature = CBW_SIGNATURE; | ||||
|     cmd.tag = CBW_TAG_VALUE; | ||||
|     cmd.xfer_len = 8; | ||||
|     cmd.dflags = CBWFLAGS_DIR_IN; | ||||
|     cmd.lun = 0; | ||||
|     cmd.cb_len = 12; | ||||
|     cmd.cb[0] = SCSI_READ_CAPACITY; | ||||
|  | ||||
|     return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will run mass storage class driver when usb device is detected | ||||
|  * and identified as a mass storage class device, it will continue to do the enumulate | ||||
|  * process. | ||||
|  * | ||||
|  * @param arg the argument. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| static rt_err_t rt_usbh_storage_enable(void* arg) | ||||
| { | ||||
|     int i = 0; | ||||
|     rt_err_t ret; | ||||
|     ustor_t stor; | ||||
|     struct uhintf* intf = (struct uhintf*)arg; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     if(intf == RT_NULL) | ||||
|     { | ||||
|         rt_kprintf("the interface is not available\n"); | ||||
|         return -RT_EIO; | ||||
|     } | ||||
|  | ||||
|     LOG_D("subclass %d, protocal %d", | ||||
|         intf->intf_desc->bInterfaceSubClass, | ||||
|         intf->intf_desc->bInterfaceProtocol); | ||||
|  | ||||
|     LOG_D("rt_usbh_storage_run"); | ||||
|  | ||||
|     /* only support SCSI subclass and bulk only protocal */ | ||||
|  | ||||
|     stor = rt_malloc(sizeof(struct ustor)); | ||||
|     RT_ASSERT(stor != RT_NULL); | ||||
|  | ||||
|     /* initilize the data structure */ | ||||
|     rt_memset(stor, 0, sizeof(struct ustor)); | ||||
|     intf->user_data = (void*)stor; | ||||
|  | ||||
|     for(i=0; i<intf->intf_desc->bNumEndpoints; i++) | ||||
|     { | ||||
|         uep_desc_t ep_desc; | ||||
|  | ||||
|         /* get endpoint descriptor from interface descriptor */ | ||||
|         rt_usbh_get_endpoint_descriptor(intf->intf_desc, i, &ep_desc); | ||||
|         if(ep_desc == RT_NULL) | ||||
|         { | ||||
|             rt_kprintf("rt_usb_get_endpoint_descriptor error\n"); | ||||
|             return -RT_ERROR; | ||||
|         } | ||||
|  | ||||
|         /* the endpoint type of mass storage class should be BULK */ | ||||
|         if((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK) | ||||
|             continue; | ||||
|  | ||||
|         /* allocate pipes according to the endpoint type */ | ||||
|         if(ep_desc->bEndpointAddress & USB_DIR_IN) | ||||
|         { | ||||
|             /* alloc an in pipe for the storage instance */ | ||||
|             stor->pipe_in = rt_usb_instance_find_pipe(intf->device,ep_desc->bEndpointAddress); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             /* alloc an output pipe for the storage instance */ | ||||
|             stor->pipe_out = rt_usb_instance_find_pipe(intf->device,ep_desc->bEndpointAddress); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* check pipes infomation */ | ||||
|     if(stor->pipe_in == RT_NULL || stor->pipe_out == RT_NULL) | ||||
|     { | ||||
|         rt_kprintf("pipe error, unsupported device\n"); | ||||
|         return -RT_ERROR; | ||||
|     } | ||||
|  | ||||
|     /* should implement as callback */ | ||||
|     ret = rt_udisk_run(intf); | ||||
|     if(ret != RT_EOK) return ret; | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will be invoked when usb device plug out is detected and it would clean | ||||
|  * and release all mass storage class related resources. | ||||
|  * | ||||
|  * @param arg the argument. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| static rt_err_t rt_usbh_storage_disable(void* arg) | ||||
| { | ||||
|     ustor_t stor; | ||||
|     struct uhintf* intf = (struct uhintf*)arg; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(intf != RT_NULL); | ||||
|     RT_ASSERT(intf->user_data != RT_NULL); | ||||
|     RT_ASSERT(intf->device != RT_NULL); | ||||
|  | ||||
|     LOG_D("rt_usbh_storage_stop"); | ||||
|  | ||||
|     /* get storage instance from interface instance */ | ||||
|     stor = (ustor_t)intf->user_data; | ||||
|  | ||||
|     rt_udisk_stop(intf); | ||||
|  | ||||
|  | ||||
|     /* free storage instance */ | ||||
|     if(stor != RT_NULL) rt_free(stor); | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will register mass storage class driver to the usb class driver manager. | ||||
|  * and it should be invoked in the usb system initialization. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| ucd_t rt_usbh_class_driver_storage(void) | ||||
| { | ||||
|     storage_driver.class_code = USB_CLASS_MASS_STORAGE; | ||||
|  | ||||
|     storage_driver.enable = rt_usbh_storage_enable; | ||||
|     storage_driver.disable = rt_usbh_storage_disable; | ||||
|  | ||||
|     return &storage_driver; | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										50
									
								
								riscv/rtthread/components/drivers/usb/usbhost/class/mass.h
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										50
									
								
								riscv/rtthread/components/drivers/usb/usbhost/class/mass.h
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2023, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2011-12-12     Yi Qiu      first version | ||||
|  */ | ||||
|  | ||||
| #ifndef __MASS_H__ | ||||
| #define __MASS_H__ | ||||
|  | ||||
| #include <rtthread.h> | ||||
| #include "dfs_fs.h" | ||||
|  | ||||
| #define MAX_PARTITION_COUNT        4 | ||||
| #define SECTOR_SIZE                512 | ||||
|  | ||||
| struct ustor_data | ||||
| { | ||||
|     struct dfs_partition part; | ||||
|     struct uhintf* intf; | ||||
|     int udisk_id; | ||||
|     const char path; | ||||
| }; | ||||
|  | ||||
| struct ustor | ||||
| { | ||||
|     upipe_t pipe_in; | ||||
|     upipe_t pipe_out; | ||||
|     rt_uint32_t capicity[2]; | ||||
|  | ||||
|     struct rt_device dev[MAX_PARTITION_COUNT]; | ||||
|     rt_uint8_t dev_cnt; | ||||
| }; | ||||
| typedef struct ustor* ustor_t; | ||||
|  | ||||
| rt_err_t rt_usbh_storage_get_max_lun(struct uhintf* intf, rt_uint8_t* max_lun); | ||||
| rt_err_t rt_usbh_storage_reset(struct uhintf* intf); | ||||
| rt_err_t rt_usbh_storage_read10(struct uhintf* intf, rt_uint8_t *buffer, | ||||
|     rt_uint32_t sector, rt_size_t count, int timeout); | ||||
| rt_err_t rt_usbh_storage_write10(struct uhintf* intf, rt_uint8_t *buffer, | ||||
|     rt_uint32_t sector, rt_size_t count, int timeout); | ||||
| rt_err_t rt_usbh_storage_request_sense(struct uhintf* intf, rt_uint8_t* buffer); | ||||
| rt_err_t rt_usbh_storage_test_unit_ready(struct uhintf* intf); | ||||
| rt_err_t rt_usbh_storage_inquiry(struct uhintf* intf, rt_uint8_t* buffer); | ||||
| rt_err_t rt_usbh_storage_get_capacity(struct uhintf* intf, rt_uint8_t* buffer); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										456
									
								
								riscv/rtthread/components/drivers/usb/usbhost/class/udisk.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										456
									
								
								riscv/rtthread/components/drivers/usb/usbhost/class/udisk.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,456 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2023, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2011-12-12     Yi Qiu      first version | ||||
|  */ | ||||
|  | ||||
| #include <rtthread.h> | ||||
| #include <dfs_fs.h> | ||||
| #include <drivers/usb_host.h> | ||||
| #include "mass.h" | ||||
|  | ||||
| #define DBG_TAG    "usbhost.udisk" | ||||
| #define DBG_LVL           DBG_INFO | ||||
| #include <rtdbg.h> | ||||
|  | ||||
| #ifdef RT_USBH_MSTORAGE | ||||
|  | ||||
| #define UDISK_MAX_COUNT        8 | ||||
| static rt_uint8_t _udisk_idset = 0; | ||||
|  | ||||
| static int udisk_get_id(void) | ||||
| { | ||||
|     int i; | ||||
|  | ||||
|     for(i=0; i< UDISK_MAX_COUNT; i++) | ||||
|     { | ||||
|         if((_udisk_idset & (1 << i)) != 0) continue; | ||||
|         else break; | ||||
|     } | ||||
|  | ||||
|     /* it should not happen */ | ||||
|     if(i == UDISK_MAX_COUNT) RT_ASSERT(0); | ||||
|  | ||||
|     _udisk_idset |= (1 << i); | ||||
|     return i; | ||||
| } | ||||
|  | ||||
| static void udisk_free_id(int id) | ||||
| { | ||||
|     RT_ASSERT(id < UDISK_MAX_COUNT) | ||||
|  | ||||
|     _udisk_idset &= ~(1 << id); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will initialize the udisk device | ||||
|  * | ||||
|  * @param dev the pointer of device driver structure | ||||
|  * | ||||
|  * @return RT_EOK | ||||
|  */ | ||||
| static rt_err_t rt_udisk_init(rt_device_t dev) | ||||
| { | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will read some data from a device. | ||||
|  * | ||||
|  * @param dev the pointer of device driver structure | ||||
|  * @param pos the position of reading | ||||
|  * @param buffer the data buffer to save read data | ||||
|  * @param size the size of buffer | ||||
|  * | ||||
|  * @return the actually read size on successful, otherwise negative returned. | ||||
|  */ | ||||
| static rt_ssize_t rt_udisk_read(rt_device_t dev, rt_off_t pos, void* buffer, | ||||
|     rt_size_t size) | ||||
| { | ||||
|     rt_err_t ret; | ||||
|     struct uhintf* intf; | ||||
|     struct ustor_data* data; | ||||
|     int timeout = USB_TIMEOUT_LONG; | ||||
|  | ||||
|     /* check parameter */ | ||||
|     RT_ASSERT(dev != RT_NULL); | ||||
|     RT_ASSERT(buffer != RT_NULL); | ||||
|  | ||||
|     if(size > 4096) timeout *= 2; | ||||
|  | ||||
|     data = (struct ustor_data*)dev->user_data; | ||||
|     intf = data->intf; | ||||
|  | ||||
|     ret = rt_usbh_storage_read10(intf, (rt_uint8_t*)buffer, pos, size, timeout); | ||||
|  | ||||
|     if (ret != RT_EOK) | ||||
|     { | ||||
|         rt_kprintf("usb mass_storage read failed\n"); | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     return size; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will write some data to a device. | ||||
|  * | ||||
|  * @param dev the pointer of device driver structure | ||||
|  * @param pos the position of written | ||||
|  * @param buffer the data buffer to be written to device | ||||
|  * @param size the size of buffer | ||||
|  * | ||||
|  * @return the actually written size on successful, otherwise negative returned. | ||||
|  */ | ||||
| static rt_ssize_t rt_udisk_write (rt_device_t dev, rt_off_t pos, const void* buffer, | ||||
|     rt_size_t size) | ||||
| { | ||||
|     rt_err_t ret; | ||||
|     struct uhintf* intf; | ||||
|     struct ustor_data* data; | ||||
|     int timeout = USB_TIMEOUT_LONG; | ||||
|  | ||||
|     /* check parameter */ | ||||
|     RT_ASSERT(dev != RT_NULL); | ||||
|     RT_ASSERT(buffer != RT_NULL); | ||||
|  | ||||
|     if(size * SECTOR_SIZE > 4096) timeout *= 2; | ||||
|  | ||||
|     data = (struct ustor_data*)dev->user_data; | ||||
|     intf = data->intf; | ||||
|  | ||||
|     ret = rt_usbh_storage_write10(intf, (rt_uint8_t*)buffer, pos, size, timeout); | ||||
|     if (ret != RT_EOK) | ||||
|     { | ||||
|         rt_kprintf("usb mass_storage write %d sector failed\n", size); | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     return size; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will execute SCSI_INQUIRY_CMD command to get inquiry data. | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @param buffer the data buffer to save inquiry data | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| static rt_err_t rt_udisk_control(rt_device_t dev, int cmd, void *args) | ||||
| { | ||||
|     ustor_t stor; | ||||
|     struct ustor_data* data; | ||||
|  | ||||
|     /* check parameter */ | ||||
|     RT_ASSERT(dev != RT_NULL); | ||||
|  | ||||
|     data = (struct ustor_data*)dev->user_data; | ||||
|     stor = (ustor_t)data->intf->user_data; | ||||
|  | ||||
|     if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME) | ||||
|     { | ||||
|         struct rt_device_blk_geometry *geometry; | ||||
|  | ||||
|         geometry = (struct rt_device_blk_geometry *)args; | ||||
|         if (geometry == RT_NULL) return -RT_ERROR; | ||||
|  | ||||
|         geometry->bytes_per_sector = SECTOR_SIZE; | ||||
|         geometry->block_size = stor->capicity[1]; | ||||
|         geometry->sector_count = stor->capicity[0]; | ||||
|     } | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
| const static struct rt_device_ops udisk_device_ops = | ||||
| { | ||||
|     rt_udisk_init, | ||||
|     RT_NULL, | ||||
|     RT_NULL, | ||||
|     rt_udisk_read, | ||||
|     rt_udisk_write, | ||||
|     rt_udisk_control | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| /** | ||||
|  * This function will run udisk driver when usb disk is detected. | ||||
|  * | ||||
|  * @param intf the usb interface instance. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_udisk_run(struct uhintf* intf) | ||||
| { | ||||
|     int i = 0; | ||||
|     rt_err_t ret; | ||||
|     char dname[8]; | ||||
|     char sname[8]; | ||||
|     rt_uint8_t max_lun, *sector, sense[18], inquiry[36]; | ||||
|     struct dfs_partition part[MAX_PARTITION_COUNT]; | ||||
|     ustor_t stor; | ||||
|  | ||||
|     /* check parameter */ | ||||
|     RT_ASSERT(intf != RT_NULL); | ||||
|  | ||||
|     /* set interface */ | ||||
| //    ret = rt_usbh_set_interface(intf->device, intf->intf_desc->bInterfaceNumber); | ||||
| //    if(ret != RT_EOK) | ||||
| //        rt_usbh_clear_feature(intf->device, 0, USB_FEATURE_ENDPOINT_HALT); | ||||
|     /* reset mass storage class device */ | ||||
|     ret = rt_usbh_storage_reset(intf); | ||||
|     if(ret != RT_EOK) return ret; | ||||
|  | ||||
|     stor = (ustor_t)intf->user_data; | ||||
|  | ||||
|     /* get max logic unit number */ | ||||
|     ret = rt_usbh_storage_get_max_lun(intf, &max_lun); | ||||
|     if(ret != RT_EOK) | ||||
|         rt_usbh_clear_feature(intf->device, 0, USB_FEATURE_ENDPOINT_HALT); | ||||
|  | ||||
|     /* reset pipe in endpoint */ | ||||
|     if(stor->pipe_in->status == UPIPE_STATUS_STALL) | ||||
|     { | ||||
|         ret = rt_usbh_clear_feature(intf->device, | ||||
|         stor->pipe_in->ep.bEndpointAddress, USB_FEATURE_ENDPOINT_HALT); | ||||
|         if(ret != RT_EOK) return ret; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /* reset pipe out endpoint */ | ||||
|     if(stor->pipe_out->status == UPIPE_STATUS_STALL) | ||||
|     { | ||||
|         ret = rt_usbh_clear_feature(intf->device, | ||||
|         stor->pipe_out->ep.bEndpointAddress, USB_FEATURE_ENDPOINT_HALT); | ||||
|         if(ret != RT_EOK) return ret; | ||||
|     } | ||||
|  | ||||
|     while((ret = rt_usbh_storage_inquiry(intf, inquiry)) != RT_EOK) | ||||
|     { | ||||
|         if(ret == -RT_EIO) return ret; | ||||
|  | ||||
|         rt_thread_delay(5); | ||||
|         if(i++ < 10) continue; | ||||
|         rt_kprintf("rt_usbh_storage_inquiry error\n"); | ||||
|         return -RT_ERROR; | ||||
|     } | ||||
|  | ||||
|     i = 0; | ||||
|  | ||||
|     /* wait device ready */ | ||||
|     while((ret = rt_usbh_storage_test_unit_ready(intf)) != RT_EOK) | ||||
|     { | ||||
|         if(ret == -RT_EIO) return ret; | ||||
|  | ||||
|         ret = rt_usbh_storage_request_sense(intf, sense); | ||||
|         if(ret == -RT_EIO) return ret; | ||||
|  | ||||
|         rt_thread_delay(10); | ||||
|         if(i++ < 10) continue; | ||||
|  | ||||
|         rt_kprintf("rt_usbh_storage_test_unit_ready error\n"); | ||||
|         return -RT_ERROR; | ||||
|     } | ||||
|  | ||||
|     i = 0; | ||||
|     rt_memset(stor->capicity, 0, sizeof(stor->capicity)); | ||||
|  | ||||
|     /* get storage capacity */ | ||||
|     while((ret = rt_usbh_storage_get_capacity(intf, | ||||
|         (rt_uint8_t*)stor->capicity)) != RT_EOK) | ||||
|     { | ||||
|         if(ret == -RT_EIO) return ret; | ||||
|  | ||||
|         rt_thread_delay(50); | ||||
|         if(i++ < 10) continue; | ||||
|  | ||||
|         stor->capicity[0] = 2880; | ||||
|         stor->capicity[1] = 0x200; | ||||
|  | ||||
|         rt_kprintf("rt_usbh_storage_get_capacity error\n"); | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     stor->capicity[0] = uswap_32(stor->capicity[0]); | ||||
|     stor->capicity[1] = uswap_32(stor->capicity[1]); | ||||
|     stor->capicity[0] += 1; | ||||
|  | ||||
|     LOG_D("capicity %d, block size %d", | ||||
|         stor->capicity[0], stor->capicity[1]); | ||||
|  | ||||
|     /* get the first sector to read partition table */ | ||||
|     sector = (rt_uint8_t*) rt_malloc (SECTOR_SIZE); | ||||
|     if (sector == RT_NULL) | ||||
|     { | ||||
|         rt_kprintf("allocate partition sector buffer failed\n"); | ||||
|         return -RT_ERROR; | ||||
|     } | ||||
|  | ||||
|     rt_memset(sector, 0, SECTOR_SIZE); | ||||
|  | ||||
|     LOG_D("read partition table"); | ||||
|  | ||||
|     /* get the partition table */ | ||||
|     ret = rt_usbh_storage_read10(intf, sector, 0, 1, USB_TIMEOUT_LONG); | ||||
|     if(ret != RT_EOK) | ||||
|     { | ||||
|         rt_kprintf("read parition table error\n"); | ||||
|  | ||||
|         rt_free(sector); | ||||
|         return -RT_ERROR; | ||||
|     } | ||||
|  | ||||
|     LOG_D("finished reading partition"); | ||||
|  | ||||
|     for(i=0; i<MAX_PARTITION_COUNT; i++) | ||||
|     { | ||||
|         /* get the first partition */ | ||||
|         ret = dfs_filesystem_get_partition(&part[i], sector, i); | ||||
|         if (ret == RT_EOK) | ||||
|         { | ||||
|             struct ustor_data* data = rt_malloc(sizeof(struct ustor_data)); | ||||
|             if (data == RT_NULL) | ||||
|             { | ||||
|                 LOG_E("Allocate partition data buffer failed."); | ||||
|                 continue; | ||||
|             } | ||||
|             rt_memset(data, 0, sizeof(struct ustor_data)); | ||||
|             data->intf = intf; | ||||
|             data->udisk_id = udisk_get_id(); | ||||
|             rt_snprintf(dname, 6, "ud%d-%d", data->udisk_id, i); | ||||
|             rt_snprintf(sname, 8, "sem_ud%d",  i); | ||||
|             data->part.lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO); | ||||
|  | ||||
|             /* register sdcard device */ | ||||
|             stor->dev[i].type    = RT_Device_Class_Block; | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
|             stor->dev[i].ops     = &udisk_device_ops; | ||||
| #else | ||||
|             stor->dev[i].init    = rt_udisk_init; | ||||
|             stor->dev[i].read    = rt_udisk_read; | ||||
|             stor->dev[i].write   = rt_udisk_write; | ||||
|             stor->dev[i].control = rt_udisk_control; | ||||
| #endif | ||||
|             stor->dev[i].user_data = (void*)data; | ||||
|  | ||||
|             rt_device_register(&stor->dev[i], dname, RT_DEVICE_FLAG_RDWR | | ||||
|                 RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE); | ||||
|  | ||||
|             stor->dev_cnt++; | ||||
|             if (dfs_mount(stor->dev[i].parent.name, UDISK_MOUNTPOINT, "elm", | ||||
|                 0, 0) == 0) | ||||
|             { | ||||
|                 LOG_D("udisk part %d mount successfully", i); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 LOG_D("udisk part %d mount failed", i); | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             if(i == 0) | ||||
|             { | ||||
|                 struct ustor_data* data = rt_malloc(sizeof(struct ustor_data)); | ||||
|                 if (data == RT_NULL) | ||||
|                 { | ||||
|                     LOG_E("Allocate partition data buffer failed."); | ||||
|                     break; | ||||
|                 } | ||||
|                 rt_memset(data, 0, sizeof(struct ustor_data)); | ||||
|                 data->udisk_id = udisk_get_id(); | ||||
|  | ||||
|                 /* there is no partition table */ | ||||
|                 data->part.offset = 0; | ||||
|                 data->part.size   = 0; | ||||
|                 data->intf = intf; | ||||
|                 data->part.lock = rt_sem_create("sem_ud", 1, RT_IPC_FLAG_FIFO); | ||||
|  | ||||
|                 rt_snprintf(dname, 7, "udisk%d", data->udisk_id); | ||||
|  | ||||
|                 /* register sdcard device */ | ||||
|                 stor->dev[0].type    = RT_Device_Class_Block; | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
|                 stor->dev[i].ops     = &udisk_device_ops; | ||||
| #else | ||||
|                 stor->dev[0].init    = rt_udisk_init; | ||||
|                 stor->dev[0].read    = rt_udisk_read; | ||||
|                 stor->dev[0].write   = rt_udisk_write; | ||||
|                 stor->dev[0].control = rt_udisk_control; | ||||
| #endif | ||||
|                 stor->dev[0].user_data = (void*)data; | ||||
|  | ||||
|                 rt_device_register(&stor->dev[0], dname, | ||||
|                     RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | ||||
|                     | RT_DEVICE_FLAG_STANDALONE); | ||||
|  | ||||
|                 stor->dev_cnt++; | ||||
|                 if (dfs_mount(stor->dev[0].parent.name, UDISK_MOUNTPOINT, | ||||
|                     "elm", 0, 0) == 0) | ||||
|                 { | ||||
|                     rt_kprintf("Mount FAT on Udisk successful.\n"); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     rt_kprintf("Mount FAT on Udisk failed.\n"); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     rt_free(sector); | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will be invoked when usb disk plug out is detected and it would clean | ||||
|  * and release all udisk related resources. | ||||
|  * | ||||
|  * @param intf the usb interface instance. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_udisk_stop(struct uhintf* intf) | ||||
| { | ||||
|     int i; | ||||
|     ustor_t stor; | ||||
|     struct ustor_data* data; | ||||
|  | ||||
|     /* check parameter */ | ||||
|     RT_ASSERT(intf != RT_NULL); | ||||
|     RT_ASSERT(intf->device != RT_NULL); | ||||
|  | ||||
|     stor = (ustor_t)intf->user_data; | ||||
|     RT_ASSERT(stor != RT_NULL); | ||||
|  | ||||
|     for(i=0; i<stor->dev_cnt; i++) | ||||
|     { | ||||
|         rt_device_t dev = &stor->dev[i]; | ||||
|         data = (struct ustor_data*)dev->user_data; | ||||
|  | ||||
|         /* unmount filesystem */ | ||||
|         dfs_unmount(UDISK_MOUNTPOINT); | ||||
|  | ||||
|         /* delete semaphore */ | ||||
|         rt_sem_delete(data->part.lock); | ||||
|         udisk_free_id(data->udisk_id); | ||||
|         rt_free(data); | ||||
|  | ||||
|         /* unregister device */ | ||||
|         rt_device_unregister(&stor->dev[i]); | ||||
|     } | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										93
									
								
								riscv/rtthread/components/drivers/usb/usbhost/class/ukbd.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										93
									
								
								riscv/rtthread/components/drivers/usb/usbhost/class/ukbd.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,93 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2023, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2012-01-03     Yi Qiu      first version | ||||
|  */ | ||||
|  | ||||
| #include <rtthread.h> | ||||
| #include <drivers/usb_host.h> | ||||
| #include "hid.h" | ||||
|  | ||||
| #if defined(RT_USBH_HID) && defined(RT_USBH_HID_KEYBOARD) | ||||
|  | ||||
| #define DBG_TAG    "usbhost.ukbd" | ||||
| #define DBG_LVL           DBG_INFO | ||||
| #include <rtdbg.h> | ||||
|  | ||||
| static struct uprotocal kbd_protocal; | ||||
|  | ||||
| static rt_err_t rt_usbh_hid_kbd_callback(void* arg) | ||||
| { | ||||
|     int int1, int2; | ||||
|     struct uhid* hid; | ||||
|  | ||||
|     hid = (struct uhid*)arg; | ||||
|  | ||||
|     int1 = *(rt_uint32_t*)hid->buffer; | ||||
|     int2 = *(rt_uint32_t*)(&hid->buffer[4]); | ||||
|  | ||||
|     if(int1 != 0 || int2 != 0) | ||||
|     { | ||||
|         LOG_D("key down 0x%x, 0x%x", int1, int2); | ||||
|     } | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| static rt_thread_t kbd_thread; | ||||
| static void kbd_task(void* param) | ||||
| { | ||||
|     struct uhintf* intf = (struct uhintf*)param; | ||||
|     while (1) | ||||
|     { | ||||
|         if (rt_usb_hcd_pipe_xfer(intf->device->hcd, ((struct uhid*)intf->user_data)->pipe_in, | ||||
|             ((struct uhid*)intf->user_data)->buffer, ((struct uhid*)intf->user_data)->pipe_in->ep.wMaxPacketSize, | ||||
|             USB_TIMEOUT_BASIC) == 0) | ||||
|         { | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         rt_usbh_hid_kbd_callback(intf->user_data); | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| static rt_err_t rt_usbh_hid_kbd_init(void* arg) | ||||
| { | ||||
|     struct uhintf* intf = (struct uhintf*)arg; | ||||
|  | ||||
|     RT_ASSERT(intf != RT_NULL); | ||||
|  | ||||
|     rt_usbh_hid_set_protocal(intf, 0); | ||||
|  | ||||
|     rt_usbh_hid_set_idle(intf, 10, 0); | ||||
|  | ||||
|     LOG_D("start usb keyboard"); | ||||
|  | ||||
|     kbd_thread = rt_thread_create("kbd0", kbd_task, intf, 1024, 8, 100); | ||||
|     rt_thread_startup(kbd_thread); | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will define the hid keyboard protocal, it will be register to the protocal list. | ||||
|  * | ||||
|  * @return the keyboard protocal structure. | ||||
|  */ | ||||
| uprotocal_t rt_usbh_hid_protocal_kbd(void) | ||||
| { | ||||
|     kbd_protocal.pro_id = USB_HID_KEYBOARD; | ||||
|  | ||||
|     kbd_protocal.init = rt_usbh_hid_kbd_init; | ||||
|     kbd_protocal.callback = rt_usbh_hid_kbd_callback; | ||||
|  | ||||
|     return &kbd_protocal; | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										190
									
								
								riscv/rtthread/components/drivers/usb/usbhost/class/umouse.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										190
									
								
								riscv/rtthread/components/drivers/usb/usbhost/class/umouse.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,190 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2023, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2012-01-03     Yi Qiu      first version | ||||
|  */ | ||||
|  | ||||
| #include <rtthread.h> | ||||
| #include <drivers/usb_host.h> | ||||
| #include "hid.h" | ||||
|  | ||||
| #ifdef RT_USING_RTGUI | ||||
| #include <rtgui/event.h> | ||||
| #include <rtgui/rtgui_server.h> | ||||
| #include "drv_lcd.h" | ||||
| #endif | ||||
|  | ||||
| #if defined(RT_USBH_HID) && defined(RT_USBH_HID_MOUSE) | ||||
|  | ||||
| #define DBG_TAG    "usbhost.umouse" | ||||
| #define DBG_LVL           DBG_INFO | ||||
| #include <rtdbg.h> | ||||
|  | ||||
| static struct uprotocal mouse_protocal; | ||||
|  | ||||
| #ifdef RT_USING_RTGUI | ||||
| #define LKEY_PRESS 0x01 | ||||
| #define RKEY_PRESS 0x02 | ||||
| #define MKEY_PRESS 0x04 | ||||
| #define MOUSE_SCALING 0x02 | ||||
|  | ||||
| static rt_bool_t lkey_down=RT_FALSE; | ||||
| //static rt_bool_t rkey_down=RT_FALSE; | ||||
| //static rt_bool_t mkey_down=RT_FALSE; | ||||
| static struct rtgui_event_mouse emouse; | ||||
| #endif | ||||
|  | ||||
| static rt_err_t rt_usbh_hid_mouse_callback(void* arg) | ||||
| { | ||||
|     struct uhid* hid; | ||||
| #ifdef RT_USING_RTGUI | ||||
|     rt_uint16_t xoffset=0; | ||||
|     rt_uint16_t yoffset=0; | ||||
| #endif | ||||
|     hid = (struct uhid*)arg; | ||||
|  | ||||
|     LOG_D("hid 0x%x 0x%x", | ||||
|                                 *(rt_uint32_t*)hid->buffer, | ||||
|                                 *(rt_uint32_t*)(&hid->buffer[4])); | ||||
| #ifdef RT_USING_RTGUI | ||||
|     if(hid->buffer[1]!=0) | ||||
|     { | ||||
|         if(hid->buffer[1]>127) | ||||
|         { | ||||
|             xoffset=(256-hid->buffer[1])*MOUSE_SCALING; | ||||
|             if(emouse.x>xoffset) | ||||
|             { | ||||
|                 emouse.x-=xoffset; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 emouse.x=0; | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             xoffset=(hid->buffer[1])*MOUSE_SCALING; | ||||
|             if((emouse.x+xoffset)<480) | ||||
|             { | ||||
|                 emouse.x+=xoffset; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 emouse.x=480; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     if(hid->buffer[2]!=0) | ||||
|     { | ||||
|  | ||||
|         if(hid->buffer[2]>127) | ||||
|         { | ||||
|             yoffset=(256-hid->buffer[2])*MOUSE_SCALING; | ||||
|             if(emouse.y>yoffset) | ||||
|             { | ||||
|                 emouse.y-=yoffset; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 emouse.y=0; | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             yoffset=hid->buffer[2]*MOUSE_SCALING; | ||||
|             if(emouse.y+yoffset<272) | ||||
|             { | ||||
|                 emouse.y+=yoffset; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 emouse.y=272; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     if(xoffset!=0||yoffset!=0) | ||||
|     { | ||||
|         cursor_set_position(emouse.x,emouse.y); | ||||
|     } | ||||
|     if(hid->buffer[0]&LKEY_PRESS) | ||||
|     { | ||||
|         if(lkey_down==RT_FALSE) | ||||
|         { | ||||
|             // rt_kprintf("mouse left key press down\n"); | ||||
|             emouse.button = (RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_DOWN); | ||||
|             rtgui_server_post_event(&emouse.parent, sizeof(struct rtgui_event_mouse)); | ||||
|             lkey_down=RT_TRUE; | ||||
|         } | ||||
|     } | ||||
|     else if(lkey_down==RT_TRUE) | ||||
|     { | ||||
|         // rt_kprintf("mouse left key press up\n"); | ||||
|         emouse.button = (RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_UP); | ||||
|         rtgui_server_post_event(&emouse.parent, sizeof(struct rtgui_event_mouse)); | ||||
|         lkey_down=RT_FALSE; | ||||
|     } | ||||
| #endif | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| static rt_thread_t mouse_thread; | ||||
| static void mouse_task(void* param) | ||||
| { | ||||
|     struct uhintf* intf = (struct uhintf*)param; | ||||
|     while (1) | ||||
|     { | ||||
|         if (rt_usb_hcd_pipe_xfer(intf->device->hcd, ((struct uhid*)intf->user_data)->pipe_in, | ||||
|             ((struct uhid*)intf->user_data)->buffer, ((struct uhid*)intf->user_data)->pipe_in->ep.wMaxPacketSize, | ||||
|             USB_TIMEOUT_BASIC) == 0) | ||||
|         { | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         rt_usbh_hid_mouse_callback(intf->user_data); | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| static rt_err_t rt_usbh_hid_mouse_init(void* arg) | ||||
| { | ||||
|     struct uhintf* intf = (struct uhintf*)arg; | ||||
|  | ||||
|     RT_ASSERT(intf != RT_NULL); | ||||
|  | ||||
|     rt_usbh_hid_set_protocal(intf, 0); | ||||
|  | ||||
|     rt_usbh_hid_set_idle(intf, 0, 0); | ||||
|  | ||||
|     mouse_thread = rt_thread_create("mouse0", mouse_task, intf, 1024, 8, 100); | ||||
|     rt_thread_startup(mouse_thread); | ||||
|  | ||||
|     LOG_D("start usb mouse"); | ||||
| #ifdef RT_USING_RTGUI | ||||
|     RTGUI_EVENT_MOUSE_BUTTON_INIT(&emouse); | ||||
|     emouse.wid = RT_NULL; | ||||
|     cursor_display(RT_TRUE); | ||||
| #endif | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will define the hid mouse protocal, it will be register to the protocal list. | ||||
|  * | ||||
|  * @return the keyboard protocal structure. | ||||
|  */ | ||||
| uprotocal_t rt_usbh_hid_protocal_mouse(void) | ||||
| { | ||||
|     mouse_protocal.pro_id = USB_HID_MOUSE; | ||||
|  | ||||
|     mouse_protocal.init = rt_usbh_hid_mouse_init; | ||||
|     mouse_protocal.callback = rt_usbh_hid_mouse_callback; | ||||
|  | ||||
|     return &mouse_protocal; | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										147
									
								
								riscv/rtthread/components/drivers/usb/usbhost/core/driver.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										147
									
								
								riscv/rtthread/components/drivers/usb/usbhost/core/driver.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,147 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2023, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2011-03-12     Yi Qiu      first version | ||||
|  * 2021-02-23     Leslie Lee  provide possibility for multi usb host | ||||
|  */ | ||||
|  | ||||
| #include <rtthread.h> | ||||
| #include <rtservice.h> | ||||
| #include <drivers/usb_host.h> | ||||
|  | ||||
| static rt_list_t _driver_list; | ||||
| static rt_bool_t _driver_list_created = RT_FALSE; | ||||
|  | ||||
| /** | ||||
|  * This function will initilize the usb class driver related data structure, | ||||
|  * and it should be invoked in the usb system initialization. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_class_driver_init(void) | ||||
| { | ||||
|     if (_driver_list_created == RT_FALSE) | ||||
|     { | ||||
|         rt_list_init(&_driver_list); | ||||
|         _driver_list_created = RT_TRUE; | ||||
|     } | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will register an usb class driver to the class driver manager. | ||||
|  * | ||||
|  * @param drv the pointer of the usb class driver. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
|  | ||||
| rt_err_t rt_usbh_class_driver_register(ucd_t drv) | ||||
| { | ||||
|     if (drv == RT_NULL) return -RT_ERROR; | ||||
|  | ||||
|     if (rt_usbh_class_driver_find(drv->class_code, drv->subclass_code) == RT_NULL) | ||||
|     { | ||||
|         /* insert class driver into driver list */ | ||||
|         rt_list_insert_after(&_driver_list, &(drv->list)); | ||||
|     } | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will removes a previously registed usb class driver. | ||||
|  * | ||||
|  * @param drv the pointer of the usb class driver structure. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_class_driver_unregister(ucd_t drv) | ||||
| { | ||||
|     RT_ASSERT(drv != RT_NULL); | ||||
|  | ||||
|     /* remove class driver from driver list */ | ||||
|     rt_list_remove(&(drv->list)); | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will run an usb class driver. | ||||
|  * | ||||
|  * @param drv the pointer of usb class driver. | ||||
|  * @param args the parameter of run function. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_class_driver_enable(ucd_t drv, void* args) | ||||
| { | ||||
|     RT_ASSERT(drv != RT_NULL); | ||||
|  | ||||
|     if(drv->enable != RT_NULL) | ||||
|         drv->enable(args); | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will stop a usb class driver. | ||||
|  * | ||||
|  * @param drv the pointer of usb class driver structure. | ||||
|  * @param args the argument of the stop function. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_class_driver_disable(ucd_t drv, void* args) | ||||
| { | ||||
|     RT_ASSERT(drv != RT_NULL); | ||||
|  | ||||
|     if(drv->disable != RT_NULL) | ||||
|         drv->disable(args); | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * This function finds a usb class driver by specified class code and subclass code. | ||||
|  * | ||||
|  * @param class_code the usb class driver's class code. | ||||
|  * @param subclass_code the usb class driver's sub class code. | ||||
|  * | ||||
|  * @return the registered usb class driver on successful, or RT_NULL on failure. | ||||
|  */ | ||||
| ucd_t rt_usbh_class_driver_find(int class_code, int subclass_code) | ||||
| { | ||||
|     struct rt_list_node *node; | ||||
|  | ||||
|     /* enter critical */ | ||||
|     if (rt_thread_self() != RT_NULL) | ||||
|         rt_enter_critical(); | ||||
|  | ||||
|     /* try to find driver object */ | ||||
|     for (node = _driver_list.next; node != &_driver_list; node = node->next) | ||||
|     { | ||||
|         ucd_t drv = | ||||
|             (ucd_t)rt_list_entry(node, struct uclass_driver, list); | ||||
|         if (drv->class_code == class_code) | ||||
|         { | ||||
|             /* leave critical */ | ||||
|             if (rt_thread_self() != RT_NULL) | ||||
|                 rt_exit_critical(); | ||||
|  | ||||
|             return drv; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* leave critical */ | ||||
|     if (rt_thread_self() != RT_NULL) | ||||
|         rt_exit_critical(); | ||||
|  | ||||
|     /* not found */ | ||||
|     return RT_NULL; | ||||
| } | ||||
							
								
								
									
										727
									
								
								riscv/rtthread/components/drivers/usb/usbhost/core/hub.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										727
									
								
								riscv/rtthread/components/drivers/usb/usbhost/core/hub.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,727 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2023, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2011-12-12     Yi Qiu      first version | ||||
|  * 2021-02-23     Leslie Lee  provide possibility for multi usb host | ||||
|  */ | ||||
|  | ||||
| #include <rtthread.h> | ||||
| #include <drivers/usb_host.h> | ||||
|  | ||||
| #define USB_THREAD_STACK_SIZE    4096 | ||||
|  | ||||
| #define DBG_TAG    "usb.host.hub" | ||||
| #define DBG_LVL     DBG_INFO | ||||
| #include <rtdbg.h> | ||||
|  | ||||
|  | ||||
| // static struct rt_messagequeue *usb_mq; | ||||
| static struct uclass_driver hub_driver; | ||||
| // static struct uhub root_hub; | ||||
|  | ||||
| static rt_err_t root_hub_ctrl(struct uhcd *hcd, rt_uint16_t port, rt_uint8_t cmd, void *args) | ||||
| { | ||||
|     switch(cmd) | ||||
|     { | ||||
|     case RH_GET_PORT_STATUS: | ||||
|         (*(rt_uint32_t *)args) = hcd->roothub->port_status[port-1]; | ||||
|         break; | ||||
|     case RH_SET_PORT_STATUS: | ||||
|         hcd->roothub->port_status[port-1] = (*(rt_uint32_t *)args); | ||||
|         break; | ||||
|     case RH_CLEAR_PORT_FEATURE: | ||||
|         switch(((rt_uint32_t)args)) | ||||
|         { | ||||
|         case PORT_FEAT_C_CONNECTION: | ||||
|             hcd->roothub->port_status[port-1] &= ~PORT_CCSC; | ||||
|             break; | ||||
|         case PORT_FEAT_C_ENABLE: | ||||
|             hcd->roothub->port_status[port-1] &= ~PORT_PESC; | ||||
|             break; | ||||
|         case PORT_FEAT_C_SUSPEND: | ||||
|             hcd->roothub->port_status[port-1] &= ~PORT_PSSC; | ||||
|             break; | ||||
|         case PORT_FEAT_C_OVER_CURRENT: | ||||
|             hcd->roothub->port_status[port-1] &= ~PORT_POCIC; | ||||
|             break; | ||||
|         case PORT_FEAT_C_RESET: | ||||
|             hcd->roothub->port_status[port-1] &= ~PORT_PRSC; | ||||
|             break; | ||||
|         } | ||||
|         break; | ||||
|     case RH_SET_PORT_FEATURE: | ||||
|         switch((rt_uint32_t)args) | ||||
|         { | ||||
|         case PORT_FEAT_CONNECTION: | ||||
|             hcd->roothub->port_status[port-1] |= PORT_CCSC; | ||||
|             break; | ||||
|         case PORT_FEAT_ENABLE: | ||||
|             hcd->roothub->port_status[port-1] |= PORT_PESC; | ||||
|             break; | ||||
|         case PORT_FEAT_SUSPEND: | ||||
|             hcd->roothub->port_status[port-1] |= PORT_PSSC; | ||||
|             break; | ||||
|         case PORT_FEAT_OVER_CURRENT: | ||||
|             hcd->roothub->port_status[port-1] |= PORT_POCIC; | ||||
|             break; | ||||
|         case PORT_FEAT_RESET: | ||||
|             hcd->ops->reset_port(port); | ||||
|             break; | ||||
|         case PORT_FEAT_POWER: | ||||
|             break; | ||||
|         case PORT_FEAT_LOWSPEED: | ||||
|             break; | ||||
|         case PORT_FEAT_HIGHSPEED: | ||||
|             break; | ||||
|         } | ||||
|         break; | ||||
|     default: | ||||
|         return -RT_ERROR; | ||||
|     } | ||||
|     return RT_EOK; | ||||
| } | ||||
| void rt_usbh_root_hub_connect_handler(struct uhcd *hcd, rt_uint8_t port, rt_bool_t isHS) | ||||
| { | ||||
|     struct uhost_msg msg; | ||||
|     msg.type = USB_MSG_CONNECT_CHANGE; | ||||
|     msg.content.hub = hcd->roothub; | ||||
|     hcd->roothub->port_status[port - 1] |= PORT_CCS | PORT_CCSC; | ||||
|     if(isHS) | ||||
|     { | ||||
|         hcd->roothub->port_status[port - 1] &= ~PORT_LSDA; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         hcd->roothub->port_status[port - 1] |= PORT_LSDA; | ||||
|     } | ||||
|     rt_usbh_event_signal(hcd, &msg); | ||||
| } | ||||
|  | ||||
| void rt_usbh_root_hub_disconnect_handler(struct uhcd *hcd, rt_uint8_t port) | ||||
| { | ||||
|     struct uhost_msg msg; | ||||
|     msg.type = USB_MSG_CONNECT_CHANGE; | ||||
|     msg.content.hub = hcd->roothub; | ||||
|     hcd->roothub->port_status[port - 1] |= PORT_CCSC; | ||||
|     hcd->roothub->port_status[port - 1] &= ~PORT_CCS; | ||||
|     rt_usbh_event_signal(hcd, &msg); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will do USB_REQ_GET_DESCRIPTOR bRequest for the device instance | ||||
|  * to get usb hub descriptor. | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @buffer the data buffer to save usb hub descriptor. | ||||
|  * @param nbytes the size of buffer | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_hub_get_descriptor(struct uinstance* device, rt_uint8_t *buffer, rt_size_t nbytes) | ||||
| { | ||||
|     struct urequest setup; | ||||
|     int timeout = USB_TIMEOUT_BASIC; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(device != RT_NULL); | ||||
|  | ||||
|     setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_DEVICE; | ||||
|     setup.bRequest = USB_REQ_GET_DESCRIPTOR; | ||||
|     setup.wIndex = 0; | ||||
|     setup.wLength = nbytes; | ||||
|     setup.wValue = USB_DESC_TYPE_HUB << 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) | ||||
|         { | ||||
|             return RT_EOK; | ||||
|         } | ||||
|     } | ||||
|     return -RT_FALSE; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will do USB_REQ_GET_STATUS bRequest for the device instance | ||||
|  * to get usb hub status. | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @buffer the data buffer to save usb hub status. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_hub_get_status(struct uinstance* device, rt_uint32_t* buffer) | ||||
| { | ||||
|     struct urequest setup; | ||||
|     int timeout = USB_TIMEOUT_BASIC; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(device != RT_NULL); | ||||
|  | ||||
|     setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_DEVICE; | ||||
|     setup.bRequest = USB_REQ_GET_STATUS; | ||||
|     setup.wIndex = 0; | ||||
|     setup.wLength = 4; | ||||
|     setup.wValue = 0; | ||||
|     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, 4, timeout) == 4) | ||||
|         { | ||||
|             return RT_EOK; | ||||
|         } | ||||
|     } | ||||
|     return -RT_FALSE; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will do USB_REQ_GET_STATUS bRequest for the device instance | ||||
|  * to get hub port status. | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @port the hub port to get status. | ||||
|  * @buffer the data buffer to save usb hub status. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_hub_get_port_status(uhub_t hub, rt_uint16_t port, rt_uint32_t* buffer) | ||||
| { | ||||
|     struct urequest setup; | ||||
|     int timeout = USB_TIMEOUT_BASIC; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(hub != RT_NULL); | ||||
|  | ||||
|     /* get roothub port status */ | ||||
|     if(hub->is_roothub) | ||||
|     { | ||||
|         root_hub_ctrl(hub->hcd, port, RH_GET_PORT_STATUS, | ||||
|             (void*)buffer); | ||||
|         return RT_EOK; | ||||
|     } | ||||
|  | ||||
|     setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_OTHER; | ||||
|     setup.bRequest = USB_REQ_GET_STATUS; | ||||
|     setup.wIndex = port; | ||||
|     setup.wLength = 4; | ||||
|     setup.wValue = 0; | ||||
|  | ||||
|     if(rt_usb_hcd_setup_xfer(hub->hcd, hub->self->pipe_ep0_out, &setup, timeout) == 8) | ||||
|     { | ||||
|         if(rt_usb_hcd_pipe_xfer(hub->hcd, hub->self->pipe_ep0_in, buffer, 4, timeout) == 4) | ||||
|         { | ||||
|             return RT_EOK; | ||||
|         } | ||||
|     } | ||||
|     return -RT_FALSE; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will do USB_REQ_CLEAR_FEATURE bRequest for the device instance | ||||
|  * to clear feature of the hub port. | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @port the hub port. | ||||
|  * @feature feature to be cleared. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_hub_clear_port_feature(uhub_t hub, rt_uint16_t port, rt_uint16_t feature) | ||||
| { | ||||
|     struct urequest setup; | ||||
|     int timeout = USB_TIMEOUT_BASIC; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(hub != RT_NULL); | ||||
|  | ||||
|     /* clear roothub feature */ | ||||
|     if(hub->is_roothub) | ||||
|     { | ||||
|         root_hub_ctrl(hub->hcd, port, RH_CLEAR_PORT_FEATURE, | ||||
|             (void*)(rt_uint32_t)feature); | ||||
|         return RT_EOK; | ||||
|     } | ||||
|  | ||||
|     setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS | | ||||
|         USB_REQ_TYPE_OTHER; | ||||
|     setup.bRequest = USB_REQ_CLEAR_FEATURE; | ||||
|     setup.wIndex = port; | ||||
|     setup.wLength = 0; | ||||
|     setup.wValue = feature; | ||||
|  | ||||
|     if(rt_usb_hcd_setup_xfer(hub->hcd, hub->self->pipe_ep0_out, &setup, timeout) == 8) | ||||
|     { | ||||
|         return RT_EOK; | ||||
|     } | ||||
|     return -RT_FALSE; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will do USB_REQ_SET_FEATURE bRequest for the device instance | ||||
|  * to set feature of the hub port. | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @port the hub port. | ||||
|  * @feature feature to be set. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_hub_set_port_feature(uhub_t hub, rt_uint16_t port, | ||||
|     rt_uint16_t feature) | ||||
| { | ||||
|     struct urequest setup; | ||||
|     int timeout = USB_TIMEOUT_BASIC; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(hub != RT_NULL); | ||||
|  | ||||
|     /* clear roothub feature */ | ||||
|     if(hub->is_roothub) | ||||
|     { | ||||
|         root_hub_ctrl(hub->hcd, port, RH_SET_PORT_FEATURE, | ||||
|             (void*)(rt_uint32_t)feature); | ||||
|         return RT_EOK; | ||||
|     } | ||||
|  | ||||
|     setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS | | ||||
|         USB_REQ_TYPE_OTHER; | ||||
|     setup.bRequest = USB_REQ_SET_FEATURE; | ||||
|     setup.wIndex = port; | ||||
|     setup.wLength = 0; | ||||
|     setup.wValue = feature; | ||||
|  | ||||
|     if(rt_usb_hcd_setup_xfer(hub->hcd, hub->self->pipe_ep0_out, &setup, timeout) == 8) | ||||
|     { | ||||
|         return RT_EOK; | ||||
|     } | ||||
|     else return -RT_FALSE; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will rest hub port, it is invoked when sub device attached to the hub port. | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * @param port the hub port. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_hub_reset_port(uhub_t hub, rt_uint16_t port) | ||||
| { | ||||
|     rt_err_t ret; | ||||
|     rt_uint32_t pstatus; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(hub != RT_NULL); | ||||
|  | ||||
|     rt_thread_delay(50); | ||||
|  | ||||
|     /* reset hub port */ | ||||
|     ret = rt_usbh_hub_set_port_feature(hub, port, PORT_FEAT_RESET); | ||||
|     if(ret != RT_EOK) return ret; | ||||
|  | ||||
|     while(1) | ||||
|     { | ||||
|         ret = rt_usbh_hub_get_port_status(hub, port, &pstatus); | ||||
|         if(!(pstatus & PORT_PRS)) break; | ||||
|     } | ||||
|  | ||||
|     /* clear port reset feature */ | ||||
|     ret = rt_usbh_hub_clear_port_feature(hub, port, PORT_FEAT_C_RESET); | ||||
|     if(ret != RT_EOK) return ret; | ||||
|  | ||||
|     rt_thread_delay(50); | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will do debouce, it is invoked when sub device attached to the hub port. | ||||
|  * | ||||
|  * @param device the usb instance. | ||||
|  * @param port the hub port. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_hub_port_debounce(uhub_t hub, rt_uint16_t port) | ||||
| { | ||||
|     rt_err_t ret; | ||||
|     int i = 0, times = 20; | ||||
|     rt_uint32_t pstatus; | ||||
|     rt_bool_t connect = RT_TRUE; | ||||
|     int delayticks = USB_DEBOUNCE_TIME / times; | ||||
|     if (delayticks < 1) | ||||
|         delayticks = 1; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(hub != RT_NULL); | ||||
|  | ||||
|     for(i=0; i<times; i++) | ||||
|     { | ||||
|         ret = rt_usbh_hub_get_port_status(hub, port, &pstatus); | ||||
|         if(ret != RT_EOK) return ret; | ||||
|  | ||||
|         if(!(pstatus & PORT_CCS)) | ||||
|         { | ||||
|             connect = RT_FALSE; | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         rt_thread_delay(delayticks); | ||||
|     } | ||||
|  | ||||
|     if(connect) return RT_EOK; | ||||
|     else return -RT_ERROR; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will poll all the hub ports to detect port status, especially connect and | ||||
|  * disconnect events. | ||||
|  * | ||||
|  * @param intf the interface instance. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| static rt_err_t rt_usbh_hub_port_change(uhub_t hub) | ||||
| { | ||||
|     int i; | ||||
|     rt_bool_t reconnect; | ||||
|  | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(hub != RT_NULL); | ||||
|  | ||||
|     /* get usb device instance */ | ||||
|     for (i = 0; i < hub->num_ports; i++) | ||||
|     { | ||||
|         rt_err_t ret; | ||||
|         struct uinstance* device; | ||||
|         rt_uint32_t pstatus = 0; | ||||
|  | ||||
|         reconnect = RT_FALSE; | ||||
|  | ||||
|         /* get hub port status */ | ||||
|         ret = rt_usbh_hub_get_port_status(hub, i + 1, &pstatus); | ||||
|         if(ret != RT_EOK) continue; | ||||
|  | ||||
|         LOG_D("port %d status 0x%x", i + 1, pstatus); | ||||
|  | ||||
|         /* check port status change */ | ||||
|         if (pstatus & PORT_CCSC) | ||||
|         { | ||||
|             /* clear port status change feature */ | ||||
|             rt_usbh_hub_clear_port_feature(hub, i + 1, PORT_FEAT_C_CONNECTION); | ||||
|             reconnect = RT_TRUE; | ||||
|         } | ||||
|  | ||||
|         if(pstatus & PORT_PESC) | ||||
|         { | ||||
|             rt_usbh_hub_clear_port_feature(hub, i + 1, PORT_FEAT_C_ENABLE); | ||||
|             reconnect = RT_TRUE; | ||||
|         } | ||||
|  | ||||
|         if(reconnect) | ||||
|         { | ||||
|             if(hub->child[i] != RT_NULL && hub->child[i]->status != DEV_STATUS_IDLE) | ||||
|             { | ||||
|                 rt_usbh_detach_instance(hub->child[i]); | ||||
|  | ||||
|                 /* Child device have been detach. Set hub->child[i] to NULL. */ | ||||
|                 hub->child[i] = RT_NULL; | ||||
|             } | ||||
|  | ||||
|             ret = rt_usbh_hub_port_debounce(hub, i + 1); | ||||
|             if(ret != RT_EOK) continue; | ||||
|  | ||||
|             /* allocate an usb instance for new connected device */ | ||||
|             device = rt_usbh_alloc_instance(hub->hcd); | ||||
|             if(device == RT_NULL) break; | ||||
|  | ||||
|             /* set usb device speed */ | ||||
|             device->speed = (pstatus & PORT_LSDA) ? 1 : 0; | ||||
|             device->parent_hub = hub; | ||||
|             device->hcd = hub->hcd; | ||||
|             device->port = i + 1; | ||||
|             hub->child[i] = device; | ||||
|  | ||||
|             /* reset usb roothub port */ | ||||
|             rt_usbh_hub_reset_port(hub, i + 1); | ||||
|  | ||||
|             /* attatch the usb instance to the hcd */ | ||||
|             rt_usbh_attatch_instance(device); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function is the callback function of hub's int endpoint, it is invoked when data comes. | ||||
|  * | ||||
|  * @param context the context of the callback function. | ||||
|  * | ||||
|  * @return none. | ||||
|  */ | ||||
| static void rt_usbh_hub_irq(void* context) | ||||
| { | ||||
|     upipe_t pipe; | ||||
|     uhub_t hub; | ||||
|     int timeout = USB_TIMEOUT_BASIC; | ||||
|  | ||||
|     RT_ASSERT(context != RT_NULL); | ||||
|  | ||||
|     pipe = (upipe_t)context; | ||||
|     hub = (uhub_t)pipe->user_data; | ||||
|  | ||||
|     if(pipe->status != UPIPE_STATUS_OK) | ||||
|     { | ||||
|         LOG_D("hub irq error"); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     rt_usbh_hub_port_change(hub); | ||||
|  | ||||
|     LOG_D("hub int xfer..."); | ||||
|  | ||||
|     /* parameter check */ | ||||
|      RT_ASSERT(pipe->inst->hcd != RT_NULL); | ||||
|  | ||||
|     rt_usb_hcd_pipe_xfer(hub->self->hcd, pipe, hub->buffer, pipe->ep.wMaxPacketSize, timeout); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will run usb hub class driver when usb hub is detected and identified | ||||
|  * as a hub class device, it will continue to do the enumulate process. | ||||
|  * | ||||
|  * @param arg the argument. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
|  | ||||
| static rt_err_t rt_usbh_hub_enable(void *arg) | ||||
| { | ||||
|     int i = 0; | ||||
|     rt_err_t ret = RT_EOK; | ||||
|     uep_desc_t ep_desc = RT_NULL; | ||||
|     uhub_t hub; | ||||
|     struct uinstance* device; | ||||
|     struct uhintf* intf = (struct uhintf*)arg; | ||||
|     upipe_t pipe_in = RT_NULL; | ||||
|     int timeout = USB_TIMEOUT_LONG; | ||||
|     /* paremeter check */ | ||||
|     RT_ASSERT(intf != RT_NULL); | ||||
|  | ||||
|     /* get usb device instance */ | ||||
|     device = intf->device; | ||||
|  | ||||
|     /* create a hub instance */ | ||||
|     hub = rt_malloc(sizeof(struct uhub)); | ||||
|     RT_ASSERT(hub != RT_NULL); | ||||
|     rt_memset(hub, 0, sizeof(struct uhub)); | ||||
|  | ||||
|     /* make interface instance's user data point to hub instance */ | ||||
|     intf->user_data = (void*)hub; | ||||
|  | ||||
|     /* get hub descriptor head */ | ||||
|     ret = rt_usbh_hub_get_descriptor(device, (rt_uint8_t*)&hub->hub_desc, 8); | ||||
|     if(ret != RT_EOK) | ||||
|     { | ||||
|         rt_kprintf("get hub descriptor failed\n"); | ||||
|         return -RT_ERROR; | ||||
|     } | ||||
|  | ||||
|     /* get full hub descriptor */ | ||||
|     ret = rt_usbh_hub_get_descriptor(device, (rt_uint8_t*)&hub->hub_desc, | ||||
|         hub->hub_desc.length); | ||||
|     if(ret != RT_EOK) | ||||
|     { | ||||
|         rt_kprintf("get hub descriptor again failed\n"); | ||||
|         return -RT_ERROR; | ||||
|     } | ||||
|  | ||||
|     /* get hub ports number */ | ||||
|     /* If hub device supported ports over USB_HUB_PORT_NUM(Ex: 8 port hub). Set hub->num_ports to USB_HUB_PORT_NUM */ | ||||
|     if(hub->hub_desc.num_ports > USB_HUB_PORT_NUM) | ||||
|         hub->num_ports = USB_HUB_PORT_NUM; | ||||
|     else | ||||
|         hub->num_ports = hub->hub_desc.num_ports; | ||||
|  | ||||
|     hub->hcd = device->hcd; | ||||
|     hub->self = device; | ||||
|  | ||||
|     /* reset all hub ports */ | ||||
|     for (i = 0; i < hub->num_ports; i++) | ||||
|     { | ||||
|         rt_usbh_hub_set_port_feature(hub, i + 1, PORT_FEAT_POWER); | ||||
|         rt_thread_delay(hub->hub_desc.pwron_to_good | ||||
|             * 2 * RT_TICK_PER_SECOND / 1000 ); | ||||
|     } | ||||
|  | ||||
|     if(intf->intf_desc->bNumEndpoints != 1) | ||||
|         return -RT_ERROR; | ||||
|  | ||||
|     /* get endpoint descriptor from interface descriptor */ | ||||
|     rt_usbh_get_endpoint_descriptor(intf->intf_desc, 0, &ep_desc); | ||||
|     if(ep_desc == RT_NULL) | ||||
|     { | ||||
|         rt_kprintf("rt_usb_get_endpoint_descriptor error\n"); | ||||
|         return -RT_ERROR; | ||||
|     } | ||||
|  | ||||
|     /* the endpoint type of hub class should be interrupt */ | ||||
|     if( USB_EP_ATTR(ep_desc->bmAttributes) == USB_EP_ATTR_INT) | ||||
|     { | ||||
|         /* the endpoint direction of hub class should be in */ | ||||
|         if(ep_desc->bEndpointAddress & USB_DIR_IN) | ||||
|         { | ||||
|             /* allocate a pipe according to the endpoint type */ | ||||
|             pipe_in = rt_usb_instance_find_pipe(device,ep_desc->bEndpointAddress); | ||||
|             if(pipe_in == RT_NULL) | ||||
|             { | ||||
|                 return -RT_ERROR; | ||||
|             } | ||||
|             rt_usb_pipe_add_callback(pipe_in,rt_usbh_hub_irq); | ||||
|         } | ||||
|         else return -RT_ERROR; | ||||
|     } | ||||
|  | ||||
|     /* parameter check */ | ||||
|     RT_ASSERT(device->hcd != RT_NULL); | ||||
|     pipe_in->user_data = hub; | ||||
|     rt_usb_hcd_pipe_xfer(hub->hcd, pipe_in, hub->buffer, | ||||
|         pipe_in->ep.wMaxPacketSize, timeout); | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will be invoked when usb hub plug out is detected and it would clean | ||||
|  * and release all hub class related resources. | ||||
|  * | ||||
|  * @param arg the argument. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| static rt_err_t rt_usbh_hub_disable(void* arg) | ||||
| { | ||||
|     int i; | ||||
|     uhub_t hub; | ||||
|     struct uhintf* intf = (struct uhintf*)arg; | ||||
|  | ||||
|     /* paremeter check */ | ||||
|     RT_ASSERT(intf != RT_NULL); | ||||
|  | ||||
|     LOG_D("rt_usbh_hub_stop"); | ||||
|     hub = (uhub_t)intf->user_data; | ||||
|  | ||||
|     for(i=0; i<hub->num_ports; i++) | ||||
|     { | ||||
|         if(hub->child[i] != RT_NULL) | ||||
|             rt_usbh_detach_instance(hub->child[i]); | ||||
|     } | ||||
|  | ||||
|     if(hub != RT_NULL) rt_free(hub); | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will register hub class driver to the usb class driver manager. | ||||
|  * and it should be invoked in the usb system initialization. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| ucd_t rt_usbh_class_driver_hub(void) | ||||
| { | ||||
|     hub_driver.class_code = USB_CLASS_HUB; | ||||
|  | ||||
|     hub_driver.enable = rt_usbh_hub_enable; | ||||
|     hub_driver.disable = rt_usbh_hub_disable; | ||||
|  | ||||
|     return &hub_driver; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function is the main entry of usb hub thread, it is in charge of | ||||
|  * processing all messages received from the usb message buffer. | ||||
|  * | ||||
|  * @param parameter the parameter of the usb host thread. | ||||
|  * | ||||
|  * @return none. | ||||
|  */ | ||||
| static void rt_usbh_hub_thread_entry(void* parameter) | ||||
| { | ||||
|     uhcd_t hcd = (uhcd_t)parameter; | ||||
|     while(1) | ||||
|     { | ||||
|         struct uhost_msg msg; | ||||
|  | ||||
|         /* receive message */ | ||||
|         if (rt_mq_recv(hcd->usb_mq, &msg, sizeof(struct uhost_msg), RT_WAITING_FOREVER) < 0) | ||||
|             continue; | ||||
|  | ||||
|         switch (msg.type) | ||||
|         { | ||||
|         case USB_MSG_CONNECT_CHANGE: | ||||
|             rt_usbh_hub_port_change(msg.content.hub); | ||||
|             break; | ||||
|         case USB_MSG_CALLBACK: | ||||
|             /* invoke callback */ | ||||
|             msg.content.cb.function(msg.content.cb.context); | ||||
|             break; | ||||
|         default: | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will post an message to the usb message queue, | ||||
|  * | ||||
|  * @param msg the message to be posted | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| rt_err_t rt_usbh_event_signal(uhcd_t hcd, struct uhost_msg* msg) | ||||
| { | ||||
|     RT_ASSERT(msg != RT_NULL); | ||||
|  | ||||
|     /* send message to usb message queue */ | ||||
|     rt_mq_send(hcd->usb_mq, (void*)msg, sizeof(struct uhost_msg)); | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will initialize usb hub thread. | ||||
|  * | ||||
|  * @return none. | ||||
|  * | ||||
|  */ | ||||
| void rt_usbh_hub_init(uhcd_t hcd) | ||||
| { | ||||
|     rt_thread_t thread; | ||||
|     /* create root hub for hcd */ | ||||
|     hcd->roothub = rt_malloc(sizeof(struct uhub)); | ||||
|     if(hcd->roothub == RT_NULL) | ||||
|     { | ||||
|         LOG_E("hcd->roothub: allocate buffer failed."); | ||||
|         return; | ||||
|     } | ||||
|     rt_memset(hcd->roothub, 0, sizeof(struct uhub)); | ||||
|     hcd->roothub->is_roothub = RT_TRUE; | ||||
|     hcd->roothub->hcd = hcd; | ||||
|     hcd->roothub->num_ports = hcd->num_ports; | ||||
|     /* create usb message queue */ | ||||
|  | ||||
|     hcd->usb_mq = rt_mq_create(hcd->parent.parent.name, 32, 16, RT_IPC_FLAG_FIFO); | ||||
|  | ||||
|     /* create usb hub thread */ | ||||
|     thread = rt_thread_create(hcd->parent.parent.name, rt_usbh_hub_thread_entry, hcd, | ||||
|         USB_THREAD_STACK_SIZE, 8, 20); | ||||
|     if(thread != RT_NULL) | ||||
|     { | ||||
|         /* startup usb host thread */ | ||||
|         rt_thread_startup(thread); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										76
									
								
								riscv/rtthread/components/drivers/usb/usbhost/core/usbhost.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										76
									
								
								riscv/rtthread/components/drivers/usb/usbhost/core/usbhost.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2023, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2011-12-12     Yi Qiu      first version | ||||
|  * 2021-02-23     Leslie Lee  provide possibility for multi usb host | ||||
|  */ | ||||
| #include <rtthread.h> | ||||
| #include <drivers/usb_host.h> | ||||
|  | ||||
| #define USB_HOST_CONTROLLER_NAME      "usbh" | ||||
|  | ||||
| #if defined(RT_USBH_HID_KEYBOARD) || defined(RT_USBH_HID_MOUSE) | ||||
| #include <hid.h> | ||||
| #endif | ||||
|  | ||||
| /** | ||||
|  * This function will initialize the usb host stack, all the usb class driver and | ||||
|  * host controller driver are also be initialized here. | ||||
|  * | ||||
|  * @return none. | ||||
|  */ | ||||
| rt_err_t rt_usb_host_init(const char *name) | ||||
| { | ||||
|     ucd_t drv; | ||||
|     rt_device_t uhc; | ||||
|  | ||||
|     uhc = rt_device_find(name); | ||||
|     if(uhc == RT_NULL) | ||||
|     { | ||||
|         rt_kprintf("can't find usb host controller %s\n", name); | ||||
|         return -RT_ERROR; | ||||
|     } | ||||
|  | ||||
|     /* initialize usb hub */ | ||||
|     rt_usbh_hub_init((uhcd_t)uhc); | ||||
|  | ||||
|     /* initialize class driver */ | ||||
|     rt_usbh_class_driver_init(); | ||||
|  | ||||
| #ifdef RT_USBH_MSTORAGE | ||||
|     /* register mass storage class driver */ | ||||
|     drv = rt_usbh_class_driver_storage(); | ||||
|     rt_usbh_class_driver_register(drv); | ||||
| #endif | ||||
| #ifdef RT_USBH_HID | ||||
|     extern ucd_t rt_usbh_class_driver_hid(void); | ||||
|     /* register mass storage class driver */ | ||||
|     drv = rt_usbh_class_driver_hid(); | ||||
|     rt_usbh_class_driver_register(drv); | ||||
| #ifdef RT_USBH_HID_MOUSE | ||||
|     { | ||||
|         extern uprotocal_t rt_usbh_hid_protocal_mouse(void); | ||||
|         rt_usbh_hid_protocal_register(rt_usbh_hid_protocal_mouse()); | ||||
|     } | ||||
| #endif | ||||
| #ifdef RT_USBH_HID_KEYBOARD | ||||
|     { | ||||
|         extern uprotocal_t rt_usbh_hid_protocal_kbd(void); | ||||
|         rt_usbh_hid_protocal_register(rt_usbh_hid_protocal_kbd()); | ||||
|     } | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
|     /* register hub class driver */ | ||||
|     drv = rt_usbh_class_driver_hub(); | ||||
|     rt_usbh_class_driver_register(drv); | ||||
|  | ||||
|     /* initialize usb host controller */ | ||||
|     rt_device_init(uhc); | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
							
								
								
									
										586
									
								
								riscv/rtthread/components/drivers/usb/usbhost/core/usbhost_core.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										586
									
								
								riscv/rtthread/components/drivers/usb/usbhost/core/usbhost_core.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,586 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2023, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2011-12-12     Yi Qiu      first version | ||||
|  */ | ||||
|  | ||||
| #include <rtthread.h> | ||||
| #include <drivers/usb_host.h> | ||||
|  | ||||
| #define DBG_TAG    "usbhost.core" | ||||
| #define DBG_LVL           DBG_INFO | ||||
| #include <rtdbg.h> | ||||
|  | ||||
| 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; i<USB_MAX_DEVICE; i++) | ||||
|     { | ||||
|         /* to find an idle instance handle */ | ||||
|         if(dev[i].status != DEV_STATUS_IDLE) continue; | ||||
|  | ||||
|         /* initialize the usb device instance */ | ||||
|         rt_memset(&dev[i], 0, sizeof(struct uinstance)); | ||||
|  | ||||
|         dev[i].status = DEV_STATUS_BUSY; | ||||
|         dev[i].index = i + 1; | ||||
|         dev[i].address = 0; | ||||
|         dev[i].max_packet_size = 0x8; | ||||
|         rt_list_init(&dev[i].pipe); | ||||
|         dev[i].hcd = uhcd; | ||||
|         /* unlock scheduler */ | ||||
|         rt_exit_critical(); | ||||
|         return &dev[i]; | ||||
|     } | ||||
|  | ||||
|     /* unlock scheduler */ | ||||
|     rt_exit_critical(); | ||||
|  | ||||
|     return RT_NULL; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This function will attatch an usb device instance to a host controller, | ||||
|  * and do device enumunation process. | ||||
|  * | ||||
|  * @param hcd the host controller driver. | ||||
|  * @param device the usb device instance. | ||||
|  * | ||||
|  * @return the error code, RT_EOK on successfully. | ||||
|  */ | ||||
| static struct uendpoint_descriptor ep0_out_desc = | ||||
| { | ||||
|     /*endpoint descriptor*/ | ||||
|     USB_DESC_LENGTH_ENDPOINT, | ||||
|     USB_DESC_TYPE_ENDPOINT, | ||||
|     0x00 | USB_DIR_OUT, | ||||
|     USB_EP_ATTR_CONTROL, | ||||
|     0x00, | ||||
|     0x00, | ||||
| }; | ||||
| static struct uendpoint_descriptor ep0_in_desc = | ||||
| { | ||||
|     /*endpoint descriptor*/ | ||||
|     USB_DESC_LENGTH_ENDPOINT, | ||||
|     USB_DESC_TYPE_ENDPOINT, | ||||
|     0x00 | USB_DIR_IN, | ||||
|     USB_EP_ATTR_CONTROL, | ||||
|     0x00, | ||||
|     0x00, | ||||
| }; | ||||
| rt_err_t rt_usbh_attatch_instance(uinst_t device) | ||||
| { | ||||
|     int i = 0; | ||||
|     rt_err_t ret = RT_EOK; | ||||
|     struct uconfig_descriptor cfg_desc; | ||||
|     udev_desc_t dev_desc; | ||||
|     uintf_desc_t intf_desc; | ||||
|     uep_desc_t ep_desc; | ||||
|     rt_uint8_t ep_index; | ||||
|     upipe_t pipe; | ||||
|     ucd_t drv; | ||||
|  | ||||
|     RT_ASSERT(device != RT_NULL); | ||||
|  | ||||
|     rt_memset(&cfg_desc, 0, sizeof(struct uconfig_descriptor)); | ||||
|     dev_desc = &device->dev_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); | ||||
|  | ||||
|     LOG_D("start enumnation"); | ||||
|  | ||||
|     /* 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); | ||||
|     LOG_D("get device descriptor length %d", | ||||
|                                 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; | ||||
|     } | ||||
|  | ||||
|     LOG_D("Vendor ID 0x%x", dev_desc->idVendor); | ||||
|     LOG_D("Product ID 0x%x", 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); | ||||
|     if(device->cfg_desc == RT_NULL) | ||||
|     { | ||||
|         return -RT_ENOMEM; | ||||
|     } | ||||
|     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; i<device->cfg_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; | ||||
|         } | ||||
|  | ||||
|         LOG_D("interface class 0x%x, subclass 0x%x", | ||||
|                                     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)); | ||||
|             if(device->intf[i] == RT_NULL) | ||||
|             { | ||||
|                 return -RT_ENOMEM; | ||||
|             } | ||||
|             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); | ||||
|  | ||||
|             LOG_D("free interface instance %d", 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); | ||||
|  | ||||
|     LOG_D("rt_usb_set_address"); | ||||
|  | ||||
|     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; | ||||
|  | ||||
|                 LOG_D("rt_usb_get_interface_descriptor: %d", 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; | ||||
|  | ||||
|                 LOG_D("rt_usb_get_endpoint_descriptor: %d", 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 | ||||
|     { | ||||
|         LOG_D("pipe transform remain size,: %d", 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; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user