/* * Copyright : (C) 2022 Phytium Information Technology, Inc. * All Rights Reserved. * * This program is OPEN SOURCE software: you can redistribute it and/or modify it * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd, * either version 1.0 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the Phytium Public License for more details. * * * FilePath: fusb.c * Date: 2022-02-11 13:33:11 * LastEditTime: 2022-02-18 09:22:06 * Description:  This files is for implmentation of USB user API * * Modify History: * Ver   Who        Date         Changes * ----- ------     --------    -------------------------------------- * 1.0 Zhugengyu 2022/2/8 init commit */ #include #include "fdebug.h" #include "fsleep.h" #include "fusb_private.h" #include "fxhci.h" #define FUSB_DEBUG_TAG "FUSB" #define FUSB_ERROR(format, ...) FT_DEBUG_PRINT_E(FUSB_DEBUG_TAG, format, ##__VA_ARGS__) #define FUSB_WARN(format, ...) FT_DEBUG_PRINT_W(FUSB_DEBUG_TAG, format, ##__VA_ARGS__) #define FUSB_INFO(format, ...) FT_DEBUG_PRINT_I(FUSB_DEBUG_TAG, format, ##__VA_ARGS__) #define FUSB_DEBUG(format, ...) FT_DEBUG_PRINT_D(FUSB_DEBUG_TAG, format, ##__VA_ARGS__) #define FUSB_DR_DESC FUsbGenerateReqType(FUSB_REQ_DEVICE_TO_HOST, FUSB_REQ_TYPE_STANDARD, FUSB_REQ_RECP_DEV) /* * Certain Lexar / Micron USB 2.0 disks will fail the FUsbGetDescriptor(FUSB_DESC_TYPE_CONFIG) * call due to timing issues. Work around this by making extra attempts on * failure. */ #define FUSB_GET_DESCRIPTOR_RETRIES 3 /** * @name: FUsbCfgInitialize * @msg: 初始化USB实例 * @return {FError} 初始化错误码 * @param {FUsb} *instance, USB实例 * @param {const FUsbConfig} *input_config, USB输入配置 * @note 在PCIE模式下,USB Hc实例在PCIE总线发现控制器后创建 */ FError FUsbCfgInitialize(FUsb *instance, const FUsbConfig *input_config) { FASSERT(instance && input_config); FError ret = FUSB_SUCCESS; if (input_config != &instance->config) instance->config = *input_config; instance->hc = NULL; /* non usb host attached */ /* create usb hc instance, which will be add as the head of hc list */ if (NULL == FXhciHcInit(instance, instance->config.base_addr)) ret = FUSB_ERR_ALLOCATE_FAIL; if (FUSB_SUCCESS == ret) { instance->is_ready = FT_COMPONENT_IS_READY; } return ret; } /** * @name: FUsbDeInitialize * @msg: 去初始化USB实例 * @return {*} * @param {FUsb} *instance, USB实例 */ void FUsbDeInitialize(FUsb *instance) { FASSERT(instance); if (FT_COMPONENT_IS_READY != instance->is_ready) { FUSB_ERROR("USB not ready !!!"); return; } instance->is_ready = 0; return; } /** * @name: FUsbPoll * @msg: 轮询所有的USB控制器连接的所有设备, 更新设备拓扑 * @return {*} * @param {FUsb} *instance, USB实例 */ void FUsbPoll(FUsb *instance) { FASSERT(instance); if (FT_COMPONENT_IS_READY != instance->is_ready) { FUSB_ERROR("USB not ready !!!"); return; } if (FUsbPollPrepare) FUsbPollPrepare(instance); FUsbHc *controller = instance->hc; if (controller != NULL) { int i; for (i = 0; i < FUSB_MAX_DEV_NUM; i++) { if (controller->devices[i] != NULL) { controller->devices[i]->poll(controller->devices[i]); } } } return; } /** * @name: FUsbExit * @msg: 关闭所有的USB控制器,移除所有连接的设备 * @return {*} * @param {FUsb} *instance, USB实例 */ void FUsbExit(FUsb *instance) { FASSERT(instance); if (FT_COMPONENT_IS_READY != instance->is_ready) { FUSB_ERROR("USB not ready !!!"); return; } if (FUsbExitPrepare) FUsbExitPrepare(instance); FUsbHc *controller = instance->hc; if (controller != NULL) { FASSERT(controller->shutdown); controller->shutdown(controller); FUSB_FREE(instance, instance->hc); instance->hc = NULL; } return; } /** * @name: FUsbMempAllocate * @msg: 从USB内存池分配一块内存,并清零分配的空间 * @return {void *} 分配的内存空间,如果失败返回NULL * @param {FUsb} *instance, USB实例 * @param {size_t} size, 请求分配的字节数 * @param {size_t} align, 分配空间的对齐方式,起始地址按align字节对齐 */ void *FUsbMempAllocate(FUsb *instance, size_t size, size_t align) { FASSERT(instance); void *result = NULL; FUsbMemAllocator *allocator = &(instance->config.allocator); if (allocator->malloc_align) { result = allocator->malloc_align(size, align); } return result; } /** * @name: FUsbMempFree * @msg: 释放从USB内存池分配的空间 * @return {*} * @param {FUsb} *instance, USB实例 * @param {void} *ptr, 待释放空间的首地址 */ void FUsbMempFree(FUsb *instance, void *ptr) { FASSERT(instance); FUsbMemAllocator *allocator = &(instance->config.allocator); if ((NULL != ptr) && (allocator->free)) { allocator->free(ptr); } return; } #ifdef FMEMP_TAG_DEBUG void *FUsbMempAllocateTag(FUsb *instance, size_t size, size_t align, const char *file, unsigned long line, const char *msg) { FASSERT(instance); void *result = NULL; FMemp *memp = &instance->memp; if (FUSB_DEFAULT_ALIGN == align) { result = FMempCallocTag(memp, 1, size, file, line, msg); } else { result = FMempMallocAlignTag(memp, size, align, file, line, msg); if (NULL != result) { memset(result, 0, size); } } return result; } void FUsbMempFreeTag(FUsb *instance, void *ptr) { FASSERT(instance); if (NULL != ptr) FMempFreeTag(&instance->memp, ptr); return; } #endif /** * @name: FUsbAllocateHc * @msg: 创建USB控制器实例,添加到USB实例的Hc链表中 * @return {*} * @param {FUsb} *instance, USB实例 */ FUsbHc *FUsbAllocateHc(FUsb *instance) { FASSERT(instance); FUsbHc *controller = FUSB_ALLOCATE(instance, sizeof(FUsbHc), FUSB_DEFAULT_ALIGN); instance->hc = controller; return controller; } /** * @name: FUsbDetachHc * @msg: 删除USB控制器实例,从USB实例的Hc链表中删去 * @return {*} * @param {FUsbHc} *controller, USB控制器实例 */ void FUsbDetachHc(FUsbHc *controller) { if (controller == NULL) return; FUsb *instance = controller->usb; FUsbDetachDev(controller, 0); /* tear down root hub tree */ return; } /** * @name: FUsbFindValidInitFunc * @msg: 寻找特定USB设备的初始化函数 * @return {*} * @param {FUsb} *instance, USB实例 * @param {FUsbDevIndex} *index, 特定USB设备的索引 */ static FUsbDevInitHandler FUsbFindValidInitFunc(FUsb *instance, const FUsbDevIndex *index) { FASSERT(instance); u32 loop; FUsbDevInitFunc *func; FUsbDevInitHandler handler = NULL; for (loop = 0; loop < instance->dev_init_num; loop++) { func = &instance->dev_init[loop]; if ((index->category == func->index.category) && (index->class == func->index.class) && (index->sub_class == func->index.sub_class) && (index->protocol == func->index.protocol)) { handler = func->handler; } } return handler; } /** * @name: FUsbAssignDevInitFunc * @msg: 指定特定USB设备的初始化函数,供创建USB设备实例时使用 * @return {FError} 处理返回错误码 * @param {FUsb} *instance, USB实例 * @param {FUsbDevIndex} *index, 特定USB设备的索引 * @param {FUsbDevInitHandler} handler, 特定USB设备的初始化函数 */ FError FUsbAssignDevInitFunc(FUsb *instance, const FUsbDevIndex *index, FUsbDevInitHandler handler) { FASSERT(instance && index && handler); if (FUSB_MAX_DEV_TYPE_NUM == instance->dev_init_num) return FUSB_ERR_INVALID_PARA; if (NULL != FUsbFindValidInitFunc(instance, index)) { FUSB_WARN("Will remove device init for class 0x%x", index->class); } instance->dev_init[instance->dev_init_num].index = *index; instance->dev_init[instance->dev_init_num].handler = handler; instance->dev_init_num++; return FUSB_SUCCESS; } /** * @name: FUsbInitDevEntry * @msg: 初始化USB设备 * @return {*} * @param {FUsbHc} *controller, USB Hc * @param {int} slot_id,slot号 */ FUsbDev *FUsbInitDevEntry(FUsbHc *controller, int slot_id) { FASSERT(controller && controller->usb); FASSERT(FUSB_SLOT_ID_VALID(slot_id)); FUsb *instace = controller->usb; FUsbDev *dev = FUSB_ALLOCATE(instace, sizeof(FUsbDev), FUSB_DEFAULT_ALIGN); if (NULL == dev) { FUSB_ERROR("no memory to allocate device structure "); return NULL; } if (controller->devices[slot_id] != NULL) { FUSB_WARN("warning: device %d reassigned? ", slot_id); } controller->devices[slot_id] = dev; dev->controller = controller; dev->address = FUSB_NO_DEV_ADDR; dev->hub = FUSB_NO_HUB; dev->port = FUSB_NO_PORT; dev->init = FUsbNopDevInit; dev->init(controller->devices[slot_id]); return dev; } /** * @name: FUsbGetAllDevEntries * @msg: 获取USB控制器上连接的所有USB设备实例 * @return {size_t} 实际获取的USB设备实例数目 * @param {FUsbHc} *controller, USB控制器实例 * @param {FUsbDev} *devs, 放置USB设备实例的缓冲区 * @param {size_t} max_dev_num, 最多可以获取的USB设备实例数目 */ size_t FUsbGetAllDevEntries(FUsbHc *controller, FUsbDev *devs[], size_t max_dev_num) { FASSERT(controller && devs && max_dev_num > 0); size_t loop; size_t num = 0; /* loop over all dev address in case there are holes */ for (loop = 0; loop < FUSB_MAX_DEV_NUM; loop++) { if (NULL != controller->devices[loop]) { devs[num] = controller->devices[loop]; num++; /* get at most max_dev_num device entry before exit */ if (num >= max_dev_num) break; } } return num; } /** * @name: FUsbDecodeMaxPacketSz0 * @msg: 根据USB设备速度,选择最大包长度 * @return {*} 输出最大包长度 * @param {FUsbSpeed} speed, USB设备速度类型 * @param {u8} bMaxPacketSize0, 输入最大包长度 */ int FUsbDecodeMaxPacketSz0(FUsbSpeed speed, u8 bMaxPacketSize0) { switch (speed) { case FUSB_LOW_SPEED: if (bMaxPacketSize0 != 8) { FUSB_ERROR("Invalid MPS0: 0x%02x ", bMaxPacketSize0); bMaxPacketSize0 = 8; } return bMaxPacketSize0; case FUSB_FULL_SPEED: switch (bMaxPacketSize0) { case 8: case 16: case 32: case 64: return bMaxPacketSize0; default: FUSB_ERROR("Invalid MPS0: 0x%02x ", bMaxPacketSize0); return 8; } case FUSB_HIGH_SPEED: if (bMaxPacketSize0 != 64) { FUSB_ERROR("Invalid MPS0: 0x%02x ", bMaxPacketSize0); bMaxPacketSize0 = 64; } return bMaxPacketSize0; case FUSB_SUPER_SPEED: /* Intentional fallthrough */ case FUSB_SUPER_SPEED_PLUS: if (bMaxPacketSize0 != 9) { FUSB_ERROR("Invalid MPS0: 0x%02x ", bMaxPacketSize0); bMaxPacketSize0 = 9; } return 1 << bMaxPacketSize0; default: return 8; } } /** * @name: FUsbSetFeature * @msg: 标准USB主机请求,使能设备/接口/端点的某个特性 * @return {FUsbTransCode} 控制传输的返回值,小于0表示失败,大于0表示成功传输的字节数目 * @param {FUsbDev} *dev, USB设备实例 * @param {int} endp, 设备号(0x00)/接口号/端点号 * @param {int} feature, 待使能的特性 * @param {int} rtype, 请求类型,由FUsbGenerateReqType生成 */ FUsbTransCode FUsbSetFeature(FUsbDev *dev, int endp, int feature, int rtype) { FASSERT(dev && dev->controller && dev->controller->control); FUsbDevReq dr; dr.bmRequestType = rtype; dr.data_dir = FUSB_REQ_HOST_TO_DEVICE; dr.bRequest = FUSB_SET_FEATURE; dr.wValue = feature; dr.wIndex = endp; dr.wLength = 0; return dev->controller->control(dev, FUSB_OUT, sizeof(dr), &dr, 0, NULL); } /** * @name: FUsbGetStatus * @msg: 标准USB主机请求,获取设备/接口/端点的状态 * @return {FUsbTransCode} 控制传输的返回值,小于0表示失败,大于0表示成功传输的字节数目 * @param {FUsbDev} *dev, USB设备实例 * @param {int} intf,设备号(0x00)/接口号/端点号 * @param {int} rtype, 请求类型,由FUsbGenerateReqType生成 * @param {int} len, Data Stage的数据长度 * @param {void} *data, Data Stage的数据缓冲区 */ FUsbTransCode FUsbGetStatus(FUsbDev *dev, int intf, int rtype, int len, void *data) { FASSERT(dev && dev->controller && dev->controller->control); FUsbDevReq dr; dr.bmRequestType = rtype; dr.data_dir = FUSB_REQ_DEVICE_TO_HOST; dr.bRequest = FUSB_GET_STATUS; dr.wValue = 0; dr.wIndex = intf; dr.wLength = len; return dev->controller->control(dev, FUSB_IN, sizeof(dr), &dr, len, data); } /** * @name: FUsbGetDescriptor * @msg: 标准USB主机请求,获取指定描述符 * @return {FUsbTransCode} 控制传输的返回值,小于0表示失败,大于0表示成功传输的字节数目 * @param {FUsbDev} *dev, USB设备实例 * @param {int} rtype, 请求类型,由FUsbGenerateReqType生成 * @param {FUsbDescriptorType} desc_type, 描述符类型 * @param {int} desc_idx, 描述符索引 * @param {void} *data, Data Stage的数据缓冲区 * @param {size_t} len, Data Stage的数据长度 */ FUsbTransCode FUsbGetDescriptor(FUsbDev *dev, int rtype, FUsbDescriptorType desc_type, int desc_idx, void *data, size_t len) { FASSERT(dev && dev->controller && dev->controller->control); FUsbDevReq dr; int fail_tries = 0; FUsbTransCode ret = FUSB_CC_ZERO_BYTES; while (fail_tries++ < FUSB_GET_DESCRIPTOR_RETRIES) { dr.bmRequestType = rtype; dr.bRequest = FUSB_GET_DESCRIPTOR; dr.wValue = desc_type << 8 | desc_idx; dr.wIndex = 0; dr.wLength = len; ret = dev->controller->control(dev, FUSB_IN, sizeof(dr), &dr, len, data); if (ret == (int)len) break; fsleep_microsec(10); } return ret; } /** * @name: FUsbGetStringDescriptor * @msg: USB主机请求,获取字符串描述符 * @return {int} 控制传输的返回值,小于0表示失败,大于0表示成功传输的字节数目 * @param {FUsbDev} *dev, USB设备实例 * @param {int} rtype, 请求类型,由FUsbGenerateReqType生成 * @param {int} desc_type, 描述符类型 * @param {int} desc_idx, 描述符索引 * @param {int} lang_id, 语言类型 * @param {void} *data, Data Stage的数据缓冲区 * @param {size_t} len, Data Stage的数据长度 */ FUsbTransCode FUsbGetStringDescriptor(FUsbDev *dev, int rtype, FUsbDescriptorType desc_type, int desc_idx, int lang_id, void *data, size_t len) { FASSERT(dev && dev->controller && dev->controller->control); FUsbDevReq dr; int fail_tries = 0; FUsbTransCode ret = FUSB_CC_ZERO_BYTES; while (fail_tries++ < FUSB_GET_DESCRIPTOR_RETRIES) { dr.bmRequestType = rtype; dr.bRequest = FUSB_GET_DESCRIPTOR; dr.wValue = desc_type << 8 | desc_idx; dr.wIndex = lang_id; dr.wLength = len; ret = dev->controller->control(dev, FUSB_IN, sizeof(dr), &dr, len, data); if (ret == (int)len) break; fsleep_microsec(10); } return ret; } /** * @name: FUsbSetConfiguration * @msg: 标准USB主机请求,设置配置值 * @return {FUsbTransCode} 控制传输的返回值,小于0表示失败,大于0表示成功传输的字节数目 * @param {FUsbDev} *dev, USB设备实例 */ FUsbTransCode FUsbSetConfiguration(FUsbDev *dev) { FASSERT(dev && dev->controller && dev->controller->control); FUsbDevReq dr; dr.bmRequestType = 0; dr.bRequest = FUSB_SET_CONFIGURATION; dr.wValue = dev->configuration->bConfigurationValue; dr.wIndex = 0; dr.wLength = 0; return dev->controller->control(dev, FUSB_OUT, sizeof(dr), &dr, 0, NULL); } /** * @name: FUsbClearFeature * @msg: 标准USB主机请求,去使能设备/接口/端点的某个特性 * @return {FUsbTransCode} 控制传输的返回值,小于0表示失败,大于0表示成功传输的字节数目 * @param {FUsbDev} *dev, USB设备实例 * @param {int} endp, 设备号(0x00)/接口号/端点号 * @param {int} feature,待去除的特性 * @param {int} rtype, 请求类型,由FUsbGenerateReqType生成 */ FUsbTransCode FUsbClearFeature(FUsbDev *dev, int endp, int feature, int rtype) { FASSERT(dev && dev->controller && dev->controller->control); FUsbDevReq dr; dr.bmRequestType = rtype; dr.data_dir = FUSB_REQ_HOST_TO_DEVICE; dr.bRequest = FUSB_CLEAR_FEATURE; dr.wValue = feature; dr.wIndex = endp; dr.wLength = 0; return dev->controller->control(dev, FUSB_OUT, sizeof(dr), &dr, 0, NULL) < 0; } /** * @name: FUsbSpeedtoDefaultMaxPacketSz * @msg: 根据设备速度获取最大包长度 * @return {int} 最大包长度 * @param {FUsbSpeed} speed, 设备速度类型 */ int FUsbSpeedtoDefaultMaxPacketSz(FUsbSpeed speed) { switch (speed) { case FUSB_LOW_SPEED: return 8; case FUSB_FULL_SPEED: case FUSB_HIGH_SPEED: return 64; case FUSB_SUPER_SPEED: /* Intentional fallthrough */ case FUSB_SUPER_SPEED_PLUS: default: return 512; } } /** * @name: FUsbDecodeInterval * @msg: 获取USB传输间隔时间 * @return {int} 传输间隔时间, 0表示失败 * @param {FUsbSpeed} speed, USB设备速度类型 * @param {FUsbEpType} type, 端点类型 * @param {unsigned char} bInterval, 设置的间隔时间 */ static int FUsbDecodeInterval(FUsbSpeed speed, const FUsbEpType type, const unsigned char bInterval) { /* Normalize bInterval to log2 of microframes */ #define LOG2(a) ((sizeof(unsigned) << 3) - __builtin_clz(a) - 1) switch (speed) { case FUSB_LOW_SPEED: switch (type) { case FUSB_ISOCHRONOUS_EP: case FUSB_INTERRUPT_EP: return LOG2(bInterval) + 3; default: return 0; } case FUSB_FULL_SPEED: switch (type) { case FUSB_ISOCHRONOUS_EP: return (bInterval - 1) + 3; case FUSB_INTERRUPT_EP: return LOG2(bInterval) + 3; default: return 0; } case FUSB_HIGH_SPEED: switch (type) { case FUSB_ISOCHRONOUS_EP: case FUSB_INTERRUPT_EP: return bInterval - 1; default: return LOG2(bInterval); } case FUSB_SUPER_SPEED: /* Intentional fallthrough */ case FUSB_SUPER_SPEED_PLUS: switch (type) { case FUSB_ISOCHRONOUS_EP: case FUSB_INTERRUPT_EP: return bInterval - 1; default: return 0; } default: return 0; } #undef LOG2 } /** * @name: FUsbSetAddress * @msg: 获取USB设备的描述符信息,根据USB设备类型完成配置和初始化 * @return {FUsbDevAddr} 为USB设备分配的地址,-1表示USB设备初始化失败 * @param {FUsbHc} *controller, USB控制器实例 * @param {FUsbSpeed} speed, USB设备速度类型 * @param {int} hubport, USB设备连接的Hub端口号 * @param {int} hubaddr, USB设备连接Hub的地址 */ static FUsbDevAddr FUsbSetAddress(FUsbHc *controller, FUsbSpeed speed, int hubport, int hubaddr) { FASSERT(controller); FUsbDev *dev = controller->set_address(controller, speed, hubport, hubaddr); FUsbDevIndex index; FUsbDevInitHandler init_handler = NULL; FUsb *instace = controller->usb; FASSERT(instace); if (NULL == dev) { FUSB_INFO("set_address failed "); return FUSB_NO_DEV_ADDR; } FASSERT(NULL == dev->descriptor); dev->descriptor = FUSB_ALLOCATE(instace, sizeof(*dev->descriptor), FUSB_DEFAULT_ALIGN); if ((NULL == dev->descriptor) || FUsbGetDescriptor(dev, FUSB_DR_DESC, FUSB_DESC_TYPE_DEVICE, 0, dev->descriptor, sizeof(*dev->descriptor)) != sizeof(*dev->descriptor)) { FUSB_INFO("FUsbGetDescriptor(FUSB_DESC_TYPE_DEVICE) failed "); FUsbDetachDev(controller, dev->address); return FUSB_NO_DEV_ADDR; } FUSB_INFO("* found device (0x%04x:0x%04x, USB %x.%x, MPS0: %d) ", dev->descriptor->idVendor, dev->descriptor->idProduct, dev->descriptor->bcdUSB >> 8, dev->descriptor->bcdUSB & 0xff, dev->endpoints[0].maxpacketsize); FUSB_INFO("device has %d configurations ", dev->descriptor->bNumConfigurations); if (dev->descriptor->bNumConfigurations == 0) { /* device isn't usable */ FUSB_INFO("... no usable configuration! "); FUsbDetachDev(controller, dev->address); return FUSB_NO_DEV_ADDR; } u16 buf[2]; if (FUsbGetDescriptor(dev, FUSB_DR_DESC, FUSB_DESC_TYPE_CONFIG, 0, buf, sizeof(buf)) != sizeof(buf)) { FUSB_INFO("first FUsbGetDescriptor(FUSB_DESC_TYPE_CONFIG) failed "); FUsbDetachDev(controller, dev->address); return FUSB_NO_DEV_ADDR; } /* workaround for some USB devices: wait until they're ready, or * they send a NAK when they're not allowed to do. 1ms is enough */ fsleep_millisec(1); FASSERT(NULL == dev->configuration); dev->configuration = FUSB_ALLOCATE(instace, buf[1], FUSB_DEFAULT_ALIGN); if (NULL == dev->configuration) { FUSB_INFO("could not allocate %d bytes for FUSB_DESC_TYPE_CONFIG ", buf[1]); FUsbDetachDev(controller, dev->address); return FUSB_NO_DEV_ADDR; } if (FUsbGetDescriptor(dev, FUSB_DR_DESC, FUSB_DESC_TYPE_CONFIG, 0, dev->configuration, buf[1]) != buf[1]) { FUSB_INFO("FUsbGetDescriptor(FUSB_DESC_TYPE_CONFIG) failed "); FUsbDetachDev(controller, dev->address); return FUSB_NO_DEV_ADDR; } FUsbConfigurationDescriptor *cd = dev->configuration; if (cd->wTotalLength != buf[1]) { FUSB_INFO("configuration descriptor size changed, aborting "); FUsbDetachDev(controller, dev->address); return FUSB_NO_DEV_ADDR; } /* * If the device is not well known (ifnum == -1), we use the first * interface we encounter, as there was no need to implement something * else for the time being. If you need it, see the SetInterface and * GetInterface functions in the USB specification and set it yourself. */ FUSB_INFO("device has %x interfaces ", cd->bNumInterfaces); u8 *end = (void *)dev->configuration + cd->wTotalLength; FUsbInterfaceDescriptor *intf; u8 *ptr; /* Find our interface (or the first good one if we don't know) */ for (ptr = (void *)dev->configuration + sizeof(*cd);; ptr += ptr[0]) { if (ptr + 2 > end || !ptr[0] || ptr + ptr[0] > end) { FUSB_INFO("Couldn't find usable FUSB_DESC_TYPE_INTERFACE "); FUsbDetachDev(controller, dev->address); return FUSB_NO_DEV_ADDR; } if (ptr[1] != FUSB_DESC_TYPE_INTERFACE) continue; intf = (void *)ptr; if (intf->bLength != sizeof(*intf)) { FUSB_INFO("Skipping broken FUSB_DESC_TYPE_INTERFACE "); continue; } FUSB_INFO("Interface %d: class 0x%x, sub 0x%x. proto 0x%x ", intf->bInterfaceNumber, intf->bInterfaceClass, intf->bInterfaceSubClass, intf->bInterfaceProtocol); ptr += sizeof(*intf); break; } /* Gather up all endpoints belonging to this interface */ dev->num_endp = 1; for (; ptr + 2 <= end && ptr[0] && ptr + ptr[0] <= end; ptr += ptr[0]) { if (ptr[1] == FUSB_DESC_TYPE_INTERFACE || ptr[1] == FUSB_DESC_TYPE_CONFIG || (size_t)dev->num_endp >= ARRAY_SIZE(dev->endpoints)) break; if (ptr[1] != FUSB_DESC_TYPE_ENDPOINT) continue; FUsbEndpointDescriptor *desc = (void *)ptr; static const char *transfertypes[4] = { "control", "isochronous", "bulk", "interrupt" }; FUSB_INFO(" #Endpoint %d (%s), max packet size %x, type %s ", desc->bEndpointAddress & 0x7f, (desc->bEndpointAddress & 0x80) ? "in" : "out", desc->wMaxPacketSize, transfertypes[desc->bmAttributes & 0x3]); FUsbEndpoint *ep = &dev->endpoints[dev->num_endp++]; ep->dev = dev; ep->endpoint = desc->bEndpointAddress; ep->toggle = 0; ep->maxpacketsize = desc->wMaxPacketSize; ep->direction = (desc->bEndpointAddress & 0x80) ? FUSB_IN : FUSB_OUT; ep->type = desc->bmAttributes & 0x3; ep->interval = FUsbDecodeInterval(dev->speed, ep->type, desc->bInterval); } if ((controller->finish_device_config && controller->finish_device_config(dev)) || FUsbSetConfiguration(dev) < 0) { FUSB_INFO("Could not finalize device configuration "); FUsbDetachDev(controller, dev->address); return FUSB_NO_DEV_ADDR; } int class = dev->descriptor->bDeviceClass; if (class == 0) class = intf->bInterfaceClass; switch (class) { case FUSB_AUDIO_DEVICE: FUSB_INFO("Audio Class "); break; case FUSB_COMM_DEVICE: FUSB_INFO("Communication Class "); break; case FUSB_HID_DEVICE: FUSB_INFO("HID Class "); break; case FUSB_PHYSICAL_DEVICE: FUSB_INFO("Physical Class"); break; case FUSB_IMAGE_DEVICE: FUSB_INFO("Camera Class "); break; case FUSB_PRINTER_DEVICE: FUSB_INFO("Printer Class"); break; case FUSB_MASS_STORAGE_DEVICE: FUSB_INFO("Mass Storage Class "); break; case FUSB_HUB_DEVICE: FUSB_INFO("Hub Class "); break; default: FUSB_ERROR("Unsupported Class %x ", class); break; } index.category = FUSB_STANDARD_INTERFACE; index.class = class; index.sub_class = intf->bInterfaceSubClass; index.protocol = intf->bInterfaceProtocol; FUSB_INFO("class: 0x%x sub-class: 0x%x, protocol: 0x%x", index.class, index.sub_class, index.protocol); init_handler = FUsbFindValidInitFunc(instace, &index); if (NULL != init_handler) { dev->init = init_handler; dev->class = (FUsbDevClass)class; } else { FUSB_WARN("Init function for the device not found, use generic one instead !!!"); dev->init = FUsbGenericDevInit; } return dev->address; } /** * @name: FUsbDetachDev * @msg: 从USB主机移除指定USB设备(USB设备驱动使用) * @return {*} * @param {FUsbHc} *controller, USB控制器实例 * @param {int} devno, USB设备索引 * @note Should be called by the hub drivers whenever a physical detach occurs * and can be called by USB class drivers if they are unsatisfied with a * malfunctioning device. */ void FUsbDetachDev(FUsbHc *controller, int devno) { FUsb *instace = controller->usb; /* check if device exists, as we may have been called yet by the USB class driver */ if (controller->devices[devno]) { controller->devices[devno]->destroy(controller->devices[devno]); if (controller->destroy_device) controller->destroy_device(controller, devno); FUSB_FREE(instace, controller->devices[devno]->descriptor); controller->devices[devno]->descriptor = NULL; FUSB_FREE(instace, controller->devices[devno]->configuration); controller->devices[devno]->configuration = NULL; /* Tear down the device itself *after* destroy_device() * has had a chance to interrogate it. */ FUSB_FREE(instace, controller->devices[devno]); controller->devices[devno] = NULL; } return; } /** * @name: FUsbAttachDev * @msg: 向USB主机添加USB设备(USB设备驱动使用) * @return {FUsbDevAddr} 分配的USB设备地址 * @param {FUsbHc} *controller, USB控制器实例 * @param {int} hubaddress, Hub地址 * @param {int} port, 连接的Port * @param {FUsbSpeed} speed, USB设备的设置速度类型 */ FUsbDevAddr FUsbAttachDev(FUsbHc *controller, int hubaddress, int port, FUsbSpeed speed) { static const char *speeds[] = {"FULL", "LOW", "HIGH", "SUPER", "ULTRA-SUPER"}; FUSB_INFO("%s-Speed Device ", ((size_t)speed < sizeof(speeds) / sizeof(char *)) ? speeds[speed] : "Unkonwn"); FUsbDevAddr newdev = FUsbSetAddress(controller, speed, port, hubaddress); if (newdev == FUSB_NO_DEV_ADDR) return FUSB_NO_DEV_ADDR; FUsbDev *newdev_t = controller->devices[newdev]; /* determine responsible driver - current done in set_address */ newdev_t->init(newdev_t); /* init() may have called FUsbDetachDev() yet, so check */ return controller->devices[newdev] ? newdev : FUSB_NO_DEV_ADDR; } /** * @name: FUsbGenericDestory * @msg: 一般USB设备去初始化函数 * @return {*} * @param {FUsbDev} *dev, USB设备实例 */ static void FUsbGenericDestory(FUsbDev *dev) { if (FUsbGenericRemove) FUsbGenericRemove(dev); return; } /** * @name: FUsbGenericDevInit * @msg: 默认的USB设备初始化函数 * @return {*} * @param {FUsbDev} *dev, USB设备实例 */ void FUsbGenericDevInit(FUsbDev *dev) { dev->data = NULL; dev->destroy = FUsbGenericDestory; if (FUsbGenericCreate) FUsbGenericCreate(dev); if (dev->data == NULL) { FUSB_INFO("Detaching device not used by payload "); FUsbDetachDev(dev->controller, dev->address); } return; }