diff options
Diffstat (limited to 'os/hal/src')
-rw-r--r-- | os/hal/src/hal_usb_msd.c | 22 | ||||
-rw-r--r-- | os/hal/src/hal_usbh.c | 423 | ||||
-rw-r--r-- | os/hal/src/usbh/TODO.txt | 21 | ||||
-rw-r--r-- | os/hal/src/usbh/hal_usbh_aoa.c | 77 | ||||
-rw-r--r-- | os/hal/src/usbh/hal_usbh_debug.c | 145 | ||||
-rw-r--r-- | os/hal/src/usbh/hal_usbh_ftdi.c | 88 | ||||
-rw-r--r-- | os/hal/src/usbh/hal_usbh_hid.c | 62 | ||||
-rw-r--r-- | os/hal/src/usbh/hal_usbh_hub.c | 49 | ||||
-rw-r--r-- | os/hal/src/usbh/hal_usbh_msd.c | 203 | ||||
-rw-r--r-- | os/hal/src/usbh/hal_usbh_uvc.c | 53 |
10 files changed, 571 insertions, 572 deletions
diff --git a/os/hal/src/hal_usb_msd.c b/os/hal/src/hal_usb_msd.c index 6cc5386..564bad0 100644 --- a/os/hal/src/hal_usb_msd.c +++ b/os/hal/src/hal_usb_msd.c @@ -84,6 +84,19 @@ static const scsi_inquiry_response_t default_scsi_inquiry_response = { {'v',CH_KERNEL_MAJOR+'0','.',CH_KERNEL_MINOR+'0'} }; +/** + * @brief Hardcoded default SCSI unit serial number inquiry response structure. + */ +static const scsi_unit_serial_number_inquiry_response_t default_scsi_unit_serial_number_inquiry_response = +{ + 0x00, + 0x80, + 0x00, + 0x08, + "00000000" +}; + + /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ @@ -373,7 +386,8 @@ void msdStop(USBMassStorageDriver *msdp) { */ void msdStart(USBMassStorageDriver *msdp, USBDriver *usbp, BaseBlockDevice *blkdev, uint8_t *blkbuf, - const scsi_inquiry_response_t *inquiry) { + const scsi_inquiry_response_t *inquiry, + const scsi_unit_serial_number_inquiry_response_t *serialInquiry) { osalDbgCheck((msdp != NULL) && (usbp != NULL) && (blkdev != NULL) && (blkbuf != NULL)); @@ -393,6 +407,12 @@ void msdStart(USBMassStorageDriver *msdp, USBDriver *usbp, else { msdp->scsi_config.inquiry_response = inquiry; } + if (NULL == serialInquiry) { + msdp->scsi_config.unit_serial_number_inquiry_response = &default_scsi_unit_serial_number_inquiry_response; + } + else { + msdp->scsi_config.unit_serial_number_inquiry_response = serialInquiry; + } msdp->scsi_config.blkbuf = blkbuf; msdp->scsi_config.blkdev = blkdev; msdp->scsi_config.transport = &msdp->scsi_transport; diff --git a/os/hal/src/hal_usbh.c b/os/hal/src/hal_usbh.c index d242086..7dff98a 100644 --- a/os/hal/src/hal_usbh.c +++ b/os/hal/src/hal_usbh.c @@ -20,15 +20,8 @@ #if HAL_USE_USBH #include "usbh/internal.h" -#include <string.h> - -//devices #include "usbh/dev/hub.h" -#include "usbh/dev/aoa.h" -#include "usbh/dev/ftdi.h" -#include "usbh/dev/msd.h" -#include "usbh/dev/hid.h" -#include "usbh/dev/uvc.h" +#include <string.h> #if USBH_DEBUG_ENABLE_TRACE #define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) @@ -62,18 +55,15 @@ #define uerr(f, ...) do {} while(0) #endif -#if STM32_USBH_USE_OTG1 -USBHDriver USBHD1; -#endif -#if STM32_USBH_USE_OTG2 -USBHDriver USBHD2; -#endif - - static void _classdriver_process_device(usbh_device_t *dev); -static bool _classdriver_load(usbh_device_t *dev, uint8_t class, - uint8_t subclass, uint8_t protocol, uint8_t *descbuff, uint16_t rem); +static bool _classdriver_load(usbh_device_t *dev, uint8_t *descbuff, uint16_t rem); +#if HAL_USBH_USE_ADDITIONAL_CLASS_DRIVERS +#include "usbh_additional_class_drivers.h" +#ifndef HAL_USBH_ADDITIONAL_CLASS_DRIVERS +#error "Must define HAL_USBH_ADDITIONAL_CLASS_DRIVERS" +#endif +#endif /*===========================================================================*/ /* Checks. */ @@ -113,28 +103,6 @@ void usbhObjectInit(USBHDriver *usbh) { #endif } -void usbhInit(void) { -#if HAL_USBH_USE_FTDI - usbhftdiInit(); -#endif -#if HAL_USBH_USE_AOA - usbhaoaInit(); -#endif -#if HAL_USBH_USE_MSD - usbhmsdInit(); -#endif -#if HAL_USBH_USE_HID - usbhhidInit(); -#endif -#if HAL_USBH_USE_UVC - usbhuvcInit(); -#endif -#if HAL_USBH_USE_HUB - usbhhubInit(); -#endif - usbh_lld_init(); -} - void usbhStart(USBHDriver *usbh) { usbDbgInit(usbh); @@ -143,7 +111,6 @@ void usbhStart(USBHDriver *usbh) { "invalid state"); usbh_lld_start(usbh); usbh->status = USBH_STATUS_STARTED; - osalOsRescheduleS(); osalSysUnlock(); } @@ -256,6 +223,7 @@ void usbhURBObjectResetI(usbh_urb_t *urb) { usbh_lld_urb_object_reset(urb); } +/* usbhURBSubmitI may require a reschedule if called from a S-locked state */ void usbhURBSubmitI(usbh_urb_t *urb) { osalDbgCheckClassI(); _check_urb(urb); @@ -265,11 +233,8 @@ void usbhURBSubmitI(usbh_urb_t *urb) { _usbh_urb_completeI(urb, USBH_URBSTATUS_STALL); return; } - if (ep->status != USBH_EPSTATUS_OPEN) { - _usbh_urb_completeI(urb, USBH_URBSTATUS_DISCONNECTED); - return; - } - if (!(usbhDeviceGetPort(ep->device)->status & USBH_PORTSTATUS_ENABLE)) { + if ((ep->status != USBH_EPSTATUS_OPEN) + || !(usbhDeviceGetPort(ep->device)->status & USBH_PORTSTATUS_ENABLE)) { _usbh_urb_completeI(urb, USBH_URBSTATUS_DISCONNECTED); return; } @@ -277,27 +242,21 @@ void usbhURBSubmitI(usbh_urb_t *urb) { usbh_lld_urb_submit(urb); } +/* _usbh_urb_abortI may require a reschedule if called from a S-locked state */ bool _usbh_urb_abortI(usbh_urb_t *urb, usbh_urbstatus_t status) { osalDbgCheckClassI(); _check_urb(urb); + osalDbgCheck(urb->status != USBH_URBSTATUS_UNINITIALIZED); - switch (urb->status) { -/* case USBH_URBSTATUS_UNINITIALIZED: - * case USBH_URBSTATUS_INITIALIZED: - * case USBH_URBSTATUS_ERROR: - * case USBH_URBSTATUS_TIMEOUT: - * case USBH_URBSTATUS_CANCELLED: - * case USBH_URBSTATUS_STALL: - * case USBH_URBSTATUS_DISCONNECTED: - * case USBH_URBSTATUS_OK: */ - default: - /* already finished */ - _usbh_urb_completeI(urb, status); - return TRUE; - - case USBH_URBSTATUS_PENDING: + if (urb->status == USBH_URBSTATUS_PENDING) { return usbh_lld_urb_abort(urb, status); } + + /* already finished or never submitted: + * USBH_URBSTATUS_INITIALIZED, USBH_URBSTATUS_ERROR, USBH_URBSTATUS_TIMEOUT, + * USBH_URBSTATUS_CANCELLED, USBH_URBSTATUS_STALL, USBH_URBSTATUS_DISCONNECTED + * USBH_URBSTATUS_OK */ + return TRUE; } void _usbh_urb_abort_and_waitS(usbh_urb_t *urb, usbh_urbstatus_t status) { @@ -309,18 +268,14 @@ void _usbh_urb_abort_and_waitS(usbh_urb_t *urb, usbh_urbstatus_t status) { osalThreadSuspendS(&urb->abortingThread); osalDbgAssert(urb->abortingThread == 0, "maybe we should uncomment the line below"); //urb->abortingThread = 0; - } -#if !(USBH_DEBUG_ENABLE && USBH_DEBUG_ENABLE_WARNINGS) - else { + } else { + /* This call is necessary because _usbh_urb_abortI may require a reschedule */ osalOsRescheduleS(); } -#else uwarn("URB aborted"); - osalOsRescheduleS(); /* debug printing functions call I-class functions inside - which may cause a priority violation without this call */ -#endif } +/* usbhURBCancelI may require a reschedule if called from a S-locked state */ bool usbhURBCancelI(usbh_urb_t *urb) { return _usbh_urb_abortI(urb, USBH_URBSTATUS_CANCELLED); } @@ -330,36 +285,14 @@ void usbhURBCancelAndWaitS(usbh_urb_t *urb) { } msg_t usbhURBWaitTimeoutS(usbh_urb_t *urb, systime_t timeout) { - msg_t ret; - osalDbgCheckClassS(); _check_urb(urb); - - switch (urb->status) { - case USBH_URBSTATUS_INITIALIZED: - case USBH_URBSTATUS_PENDING: - ret = osalThreadSuspendTimeoutS(&urb->waitingThread, timeout); - osalDbgAssert(urb->waitingThread == 0, "maybe we should uncomment the line below"); - //urb->waitingThread = 0; - break; - - case USBH_URBSTATUS_OK: - ret = MSG_OK; - osalOsRescheduleS(); - break; - -/* case USBH_URBSTATUS_UNINITIALIZED: - * case USBH_URBSTATUS_ERROR: - * case USBH_URBSTATUS_TIMEOUT: - * case USBH_URBSTATUS_CANCELLED: - * case USBH_URBSTATUS_STALL: - * case USBH_URBSTATUS_DISCONNECTED: */ - default: - ret = MSG_RESET; - osalOsRescheduleS(); - break; + if (urb->status == USBH_URBSTATUS_OK) { + return MSG_OK; + } else if (urb->status != USBH_URBSTATUS_PENDING) { + return MSG_RESET; } - return ret; + return osalThreadSuspendTimeoutS(&urb->waitingThread, timeout); } msg_t usbhURBSubmitAndWaitS(usbh_urb_t *urb, systime_t timeout) { @@ -382,6 +315,7 @@ static inline msg_t _wakeup_message(usbh_urbstatus_t status) { return MSG_RESET; } +/* _usbh_urb_completeI may require a reschedule if called from a S-locked state */ void _usbh_urb_completeI(usbh_urb_t *urb, usbh_urbstatus_t status) { osalDbgCheckClassI(); _check_urb(urb); @@ -459,7 +393,7 @@ usbh_urbstatus_t usbhControlRequest(usbh_device_t *dev, wIndex, wLength }; - return usbhControlRequestExtended(dev, &req, buff, NULL, MS2ST(1000)); + return usbhControlRequestExtended(dev, &req, buff, NULL, HAL_USBH_CONTROL_REQUEST_DEFAULT_TIMEOUT); } /*===========================================================================*/ @@ -880,9 +814,6 @@ bool usbhDeviceReadString(usbh_device_t *dev, char *dest, uint8_t size, return HAL_SUCCESS; } - - - /*===========================================================================*/ /* Port processing functions. */ /*===========================================================================*/ @@ -925,46 +856,48 @@ static void _port_process_status_change(usbh_port_t *port) { _port_update_status(port); if (port->c_status & USBH_PORTSTATUS_C_CONNECTION) { - /* port connected status changed */ port->c_status &= ~USBH_PORTSTATUS_C_CONNECTION; usbhhubClearFeaturePort(port, USBH_PORT_FEAT_C_CONNECTION); - if ((port->status & (USBH_PORTSTATUS_CONNECTION | USBH_PORTSTATUS_ENABLE)) - == USBH_PORTSTATUS_CONNECTION) { - if (port->device.status != USBH_DEVSTATUS_DISCONNECTED) { + + if (port->device.status != USBH_DEVSTATUS_DISCONNECTED) { + if (!(port->status & USBH_PORTSTATUS_CONNECTION)) { _usbh_port_disconnected(port); } + } + } - /* connected, disabled */ + if (port->device.status == USBH_DEVSTATUS_DISCONNECTED) { + if (port->status & USBH_PORTSTATUS_CONNECTION) { _port_connected(port); - } else { - /* disconnected */ - _usbh_port_disconnected(port); } } if (port->c_status & USBH_PORTSTATUS_C_RESET) { port->c_status &= ~USBH_PORTSTATUS_C_RESET; usbhhubClearFeaturePort(port, USBH_PORT_FEAT_C_RESET); + udbgf("Port %d: reset=%d", port->number, port->status & USBH_PORTSTATUS_RESET ? 1 : 0); } if (port->c_status & USBH_PORTSTATUS_C_ENABLE) { port->c_status &= ~USBH_PORTSTATUS_C_ENABLE; usbhhubClearFeaturePort(port, USBH_PORT_FEAT_C_ENABLE); + udbgf("Port %d: enable=%d", port->number, port->status & USBH_PORTSTATUS_ENABLE ? 1 : 0); } if (port->c_status & USBH_PORTSTATUS_C_OVERCURRENT) { port->c_status &= ~USBH_PORTSTATUS_C_OVERCURRENT; usbhhubClearFeaturePort(port, USBH_PORT_FEAT_C_OVERCURRENT); + uwarnf("Port %d: overcurrent=%d", port->number, port->status & USBH_PORTSTATUS_OVERCURRENT ? 1 : 0); } if (port->c_status & USBH_PORTSTATUS_C_SUSPEND) { port->c_status &= ~USBH_PORTSTATUS_C_SUSPEND; usbhhubClearFeaturePort(port, USBH_PORT_FEAT_C_SUSPEND); + uinfof("Port %d: suspend=%d", port->number, port->status & USBH_PORTSTATUS_SUSPEND ? 1 : 0); } } - static void _port_connected(usbh_port_t *port) { /* connected */ @@ -974,9 +907,8 @@ static void _port_connected(usbh_port_t *port) { usbh_devspeed_t speed; USBH_DEFINE_BUFFER(usbh_string_descriptor_t strdesc); - uinfof("Port %d connected, wait debounce...", port->number); - port->device.status = USBH_DEVSTATUS_ATTACHED; + uinfof("Port %d: attached, wait debounce...", port->number); /* wait for attach de-bounce */ osalThreadSleepMilliseconds(HAL_USBH_PORT_DEBOUNCE_TIME); @@ -984,16 +916,26 @@ static void _port_connected(usbh_port_t *port) { /* check disconnection */ _port_update_status(port); if (port->c_status & USBH_PORTSTATUS_C_CONNECTION) { - /* connection state changed; abort */ + port->c_status &= ~USBH_PORTSTATUS_C_CONNECTION; + usbhhubClearFeaturePort(port, USBH_PORT_FEAT_C_CONNECTION); + uwarnf("Port %d: connection state changed; abort #1", port->number); goto abort; } + /* make sure that the device is still connected */ + if ((port->status & USBH_PORTSTATUS_CONNECTION) == 0) { + uwarnf("Port %d: device is disconnected", port->number); + goto abort; + } + + uinfof("Port %d: connected", port->number); port->device.status = USBH_DEVSTATUS_CONNECTED; retries = 3; reset: for (i = 0; i < 3; i++) { - uinfo("Try reset..."); + uinfof("Port %d: Try reset...", port->number); + /* TODO: check that port is actually disabled */ port->c_status &= ~(USBH_PORTSTATUS_C_RESET | USBH_PORTSTATUS_C_ENABLE); _port_reset(port); osalThreadSleepMilliseconds(20); /* give it some time to reset (min. 10ms) */ @@ -1002,8 +944,12 @@ reset: _port_update_status(port); /* check for disconnection */ - if (port->c_status & USBH_PORTSTATUS_C_CONNECTION) + if (port->c_status & USBH_PORTSTATUS_C_CONNECTION) { + port->c_status &= ~USBH_PORTSTATUS_C_CONNECTION; + usbhhubClearFeaturePort(port, USBH_PORT_FEAT_C_CONNECTION); + uwarnf("Port %d: connection state changed; abort #2", port->number); goto abort; + } /* check for reset completion */ if (port->c_status & USBH_PORTSTATUS_C_RESET) { @@ -1017,7 +963,10 @@ reset: } /* check for timeout */ - if (osalOsGetSystemTimeX() - start > HAL_USBH_PORT_RESET_TIMEOUT) break; + if (osalOsGetSystemTimeX() - start > HAL_USBH_PORT_RESET_TIMEOUT) { + uwarnf("Port %d: reset timeout", port->number); + break; + } } } @@ -1025,8 +974,7 @@ reset: goto abort; reset_success: - - uinfo("Reset OK, recovery..."); + uinfof("Port %d: Reset OK, recovery...", port->number); /* reset recovery */ osalThreadSleepMilliseconds(100); @@ -1043,19 +991,22 @@ reset_success: usbhEPOpen(&port->device.ctrl); /* device with default address (0), try enumeration */ - if (_device_enumerate(&port->device)) { + if (_device_enumerate(&port->device) != HAL_SUCCESS) { /* enumeration failed */ usbhEPClose(&port->device.ctrl); - if (!--retries) + if (!--retries) { + uwarnf("Port %d: enumeration failed; abort", port->number); goto abort; + } /* retry reset & enumeration */ + uwarnf("Port %d: enumeration failed; retry reset & enumeration", port->number); goto reset; } /* load the default language ID */ - uinfo("Loading langID0..."); + uinfof("Port %d: Loading langID0...", port->number); if (!usbhStdReqGetStringDescriptor(&port->device, 0, 0, USBH_DT_STRING_SIZE, (uint8_t *)&strdesc) && (strdesc.bLength >= 4) @@ -1063,12 +1014,12 @@ reset_success: 4, (uint8_t *)&strdesc)) { port->device.langID0 = strdesc.wData[0]; - uinfof("langID0=%04x", port->device.langID0); + uinfof("Port %d: langID0=%04x", port->number, port->device.langID0); } /* check if the device has only one configuration */ if (port->device.devDesc.bNumConfigurations == 1) { - uinfo("Device has only one configuration"); + uinfof("Port %d: device has only one configuration", port->number); _device_configure(&port->device, 0); } @@ -1076,7 +1027,7 @@ reset_success: return; abort: - uerr("Abort"); + uerrf("Port %d: abort", port->number); port->device.status = USBH_DEVSTATUS_DISCONNECTED; } @@ -1084,14 +1035,14 @@ void _usbh_port_disconnected(usbh_port_t *port) { if (port->device.status == USBH_DEVSTATUS_DISCONNECTED) return; - uinfo("Port disconnected"); + uinfof("Port %d: disconnected", port->number); /* unload drivers */ while (port->device.drivers) { usbh_baseclassdriver_t *drv = port->device.drivers; /* unload */ - uinfof("Unload driver %s", drv->info->name); + uinfof("Port %d: unload driver %s", port->number, drv->info->name); drv->info->vmt->unload(drv); /* unlink */ @@ -1100,9 +1051,7 @@ void _usbh_port_disconnected(usbh_port_t *port) { } /* close control endpoint */ - osalSysLock(); - usbhEPCloseS(&port->device.ctrl); - osalSysUnlock(); + usbhEPClose(&port->device.ctrl); /* free address */ if (port->device.address) @@ -1114,7 +1063,6 @@ void _usbh_port_disconnected(usbh_port_t *port) { } - /*===========================================================================*/ /* Hub processing functions. */ /*===========================================================================*/ @@ -1142,7 +1090,7 @@ static void _hub_process_status_change(USBHDriver *host, USBHHubDriver *hub) { uinfo("Hub status change. GET_STATUS."); _hub_update_status(host, hub); - if (hub->c_status & USBH_HUBSTATUS_C_HUB_LOCAL_POWER) { + if (hub->c_status & USBH_HUBSTATUS_C_HUB_LOCAL_POWER) { hub->c_status &= ~USBH_HUBSTATUS_C_HUB_LOCAL_POWER; uinfo("Clear USBH_HUB_FEAT_C_HUB_LOCAL_POWER"); usbhhubClearFeatureHub(host, hub, USBH_HUB_FEAT_C_HUB_LOCAL_POWER); @@ -1160,7 +1108,6 @@ static uint32_t _hub_get_status_change_bitmap(USBHDriver *host, USBHHubDriver *h osalSysLock(); uint32_t ret = hub->statuschange; hub->statuschange = 0; - osalOsRescheduleS(); osalSysUnlock(); return ret; } @@ -1226,8 +1173,8 @@ void usbhMainLoop(USBHDriver *usbh) { _hub_process(usbh, NULL); /* process connected hubs */ - USBHHubDriver *hub; - list_for_each_entry(hub, USBHHubDriver, &usbh->hubs, node) { + USBHHubDriver *hub, *temp; + list_for_each_entry_safe(hub, USBHHubDriver, temp, &usbh->hubs, node) { _hub_process(usbh, hub); } #else @@ -1236,75 +1183,78 @@ void usbhMainLoop(USBHDriver *usbh) { #endif } - /*===========================================================================*/ -/* IAD class driver. */ +/* Class driver loader. */ /*===========================================================================*/ -#if HAL_USBH_USE_IAD -static usbh_baseclassdriver_t *iad_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem); -static void iad_unload(usbh_baseclassdriver_t *drv); -static const usbh_classdriver_vmt_t usbhiadClassDriverVMT = { - iad_load, - iad_unload -}; -static const usbh_classdriverinfo_t usbhiadClassDriverInfo = { - 0xef, 0x02, 0x01, "IAD", &usbhiadClassDriverVMT -}; -static usbh_baseclassdriver_t *iad_load(usbh_device_t *dev, - const uint8_t *descriptor, uint16_t rem) { - (void)rem; +bool _usbh_match_vid_pid(usbh_device_t *dev, int32_t vid, int32_t pid) { + if (((vid < 0) || (dev->devDesc.idVendor == vid)) + && ((pid < 0) || (dev->devDesc.idProduct == pid))) + return HAL_SUCCESS; - if (descriptor[1] != USBH_DT_DEVICE) - return 0; + return HAL_FAILED; +} - uinfo("Load a driver for each IF collection."); +bool _usbh_match_descriptor(const uint8_t *descriptor, uint16_t rem, + int16_t type, int16_t _class, int16_t subclass, int16_t protocol) { - generic_iterator_t icfg; - if_iterator_t iif; - const usbh_ia_descriptor_t *last_iad = 0; + int16_t dclass, dsubclass, dprotocol; - cfg_iter_init(&icfg, dev->fullConfigurationDescriptor, - dev->basicConfigDesc.wTotalLength); - if (!icfg.valid) { - uerr("Invalid configuration descriptor."); - return 0; - } + if ((rem < descriptor[0]) || (rem < 2)) + return HAL_FAILED; - for (if_iter_init(&iif, &icfg); iif.valid; if_iter_next(&iif)) { - if (iif.iad && (iif.iad != last_iad)) { - last_iad = iif.iad; - if (_classdriver_load(dev, iif.iad->bFunctionClass, - iif.iad->bFunctionSubClass, - iif.iad->bFunctionProtocol, - (uint8_t *)iif.iad, - (uint8_t *)iif.curr - (uint8_t *)iif.iad + iif.rem) != HAL_SUCCESS) { - uwarnf("No drivers found for IF collection #%d:%d", - iif.iad->bFirstInterface, - iif.iad->bFirstInterface + iif.iad->bInterfaceCount - 1); - } - } - } + uint8_t dtype = descriptor[1]; - return 0; -} + if ((type >= 0) && (type != dtype)) + return HAL_FAILED; -static void iad_unload(usbh_baseclassdriver_t *drv) { - (void)drv; -} -#endif + switch (dtype) { + case USBH_DT_DEVICE: { + if (rem < USBH_DT_DEVICE_SIZE) + return HAL_FAILED; + const usbh_device_descriptor_t *const desc = (const usbh_device_descriptor_t *)descriptor; + dclass = desc->bDeviceClass; + dsubclass = desc->bDeviceSubClass; + dprotocol = desc->bDeviceProtocol; + } break; + case USBH_DT_INTERFACE: { + if (rem < USBH_DT_INTERFACE_SIZE) + return HAL_FAILED; + const usbh_interface_descriptor_t *const desc = (const usbh_interface_descriptor_t *)descriptor; + dclass = desc->bInterfaceClass; + dsubclass = desc->bInterfaceSubClass; + dprotocol = desc->bInterfaceProtocol; + } break; + case USBH_DT_INTERFACE_ASSOCIATION: { + if (rem < USBH_DT_INTERFACE_ASSOCIATION_SIZE) + return HAL_FAILED; + const usbh_ia_descriptor_t *const desc = (const usbh_ia_descriptor_t *)descriptor; + dclass = desc->bFunctionClass; + dsubclass = desc->bFunctionSubClass; + dprotocol = desc->bFunctionProtocol; + } break; + default: + return HAL_FAILED; + } + if (((_class < 0) || (_class == dclass)) + && ((subclass < 0) || (subclass == dsubclass)) + && ((protocol < 0) || (protocol == dprotocol))) + return HAL_SUCCESS; -/*===========================================================================*/ -/* Class driver loader. */ -/*===========================================================================*/ + return HAL_FAILED; +} static const usbh_classdriverinfo_t *usbh_classdrivers_lookup[] = { +#if HAL_USBH_USE_ADDITIONAL_CLASS_DRIVERS + /* user-defined out of tree class drivers */ + HAL_USBH_ADDITIONAL_CLASS_DRIVERS +#endif #if HAL_USBH_USE_FTDI &usbhftdiClassDriverInfo, #endif -#if HAL_USBH_USE_IAD - &usbhiadClassDriverInfo, +#if HAL_USBH_USE_HUB + &usbhhubClassDriverInfo, #endif #if HAL_USBH_USE_UVC &usbhuvcClassDriverInfo, @@ -1318,44 +1268,24 @@ static const usbh_classdriverinfo_t *usbh_classdrivers_lookup[] = { #if HAL_USBH_USE_UVC &usbhuvcClassDriverInfo, #endif -#if HAL_USBH_USE_HUB - &usbhhubClassDriverInfo, -#endif #if HAL_USBH_USE_AOA &usbhaoaClassDriverInfo, /* Leave always last */ #endif }; -static bool _classdriver_load(usbh_device_t *dev, uint8_t class, - uint8_t subclass, uint8_t protocol, uint8_t *descbuff, uint16_t rem) { +static bool _classdriver_load(usbh_device_t *dev, uint8_t *descbuff, uint16_t rem) { uint8_t i; usbh_baseclassdriver_t *drv = NULL; for (i = 0; i < sizeof_array(usbh_classdrivers_lookup); i++) { const usbh_classdriverinfo_t *const info = usbh_classdrivers_lookup[i]; - if (class == 0xff) { - /* vendor specific */ - if (info->class == 0xff) { - uinfof("Try load vendor-specific driver %s", info->name); - drv = info->vmt->load(dev, descbuff, rem); - if (drv != NULL) - goto success; - } - } else if ((info->class < 0) || ((info->class == class) - && ((info->subclass < 0) || ((info->subclass == subclass) - && ((info->protocol < 0) || (info->protocol == protocol)))))) { - uinfof("Try load driver %s", info->name); - drv = info->vmt->load(dev, descbuff, rem); -#if HAL_USBH_USE_IAD - /* special case: */ - if (info == &usbhiadClassDriverInfo) - goto success; //return HAL_SUCCESS; -#endif + uinfof("Try load driver %s", info->name); + drv = info->vmt->load(dev, descbuff, rem); - if (drv != NULL) - goto success; - } + if (drv != NULL) + goto success; } + return HAL_FAILED; success: @@ -1396,13 +1326,16 @@ static void _classdriver_process_device(usbh_device_t *dev) { usbhDevicePrintConfiguration(dev->fullConfigurationDescriptor, dev->basicConfigDesc.wTotalLength); - if (devdesc->bDeviceClass == 0) { - /* each interface defines its own device class/subclass/protocol */ - uinfo("Load a driver for each IF."); +#if HAL_USBH_USE_IAD + if (dev->devDesc.bDeviceClass == 0xef + && dev->devDesc.bDeviceSubClass == 0x02 + && dev->devDesc.bDeviceProtocol == 0x01) { + + uinfo("Load a driver for each IF collection."); generic_iterator_t icfg; if_iterator_t iif; - uint8_t last_if = 0xff; + const usbh_ia_descriptor_t *last_iad = 0; cfg_iter_init(&icfg, dev->fullConfigurationDescriptor, dev->basicConfigDesc.wTotalLength); @@ -1412,24 +1345,49 @@ static void _classdriver_process_device(usbh_device_t *dev) { } for (if_iter_init(&iif, &icfg); iif.valid; if_iter_next(&iif)) { - const usbh_interface_descriptor_t *const ifdesc = if_get(&iif); - if (ifdesc->bInterfaceNumber != last_if) { - last_if = ifdesc->bInterfaceNumber; - if (_classdriver_load(dev, ifdesc->bInterfaceClass, - ifdesc->bInterfaceSubClass, - ifdesc->bInterfaceProtocol, - (uint8_t *)ifdesc, iif.rem) != HAL_SUCCESS) { - uwarnf("No drivers found for IF #%d", ifdesc->bInterfaceNumber); + if (iif.iad && (iif.iad != last_iad)) { + last_iad = iif.iad; + if (_classdriver_load(dev, + (uint8_t *)iif.iad, + (uint8_t *)iif.curr - (uint8_t *)iif.iad + iif.rem) != HAL_SUCCESS) { + uwarnf("No drivers found for IF collection #%d:%d", + iif.iad->bFirstInterface, + iif.iad->bFirstInterface + iif.iad->bInterfaceCount - 1); } } } - } else { - if (_classdriver_load(dev, devdesc->bDeviceClass, - devdesc->bDeviceSubClass, - devdesc->bDeviceProtocol, - (uint8_t *)devdesc, USBH_DT_DEVICE_SIZE) != HAL_SUCCESS) { - uwarn("No drivers found."); + } else +#endif + if (_classdriver_load(dev, (uint8_t *)devdesc, USBH_DT_DEVICE_SIZE) != HAL_SUCCESS) { + uinfo("No drivers found for device."); + + if (devdesc->bDeviceClass == 0) { + /* each interface defines its own device class/subclass/protocol */ + uinfo("Try load a driver for each IF."); + + generic_iterator_t icfg; + if_iterator_t iif; + uint8_t last_if = 0xff; + + cfg_iter_init(&icfg, dev->fullConfigurationDescriptor, + dev->basicConfigDesc.wTotalLength); + if (!icfg.valid) { + uerr("Invalid configuration descriptor."); + goto exit; + } + + for (if_iter_init(&iif, &icfg); iif.valid; if_iter_next(&iif)) { + const usbh_interface_descriptor_t *const ifdesc = if_get(&iif); + if (ifdesc->bInterfaceNumber != last_if) { + last_if = ifdesc->bInterfaceNumber; + if (_classdriver_load(dev, (uint8_t *)ifdesc, iif.rem) != HAL_SUCCESS) { + uwarnf("No drivers found for IF #%d", ifdesc->bInterfaceNumber); + } + } + } + } else { + uwarn("Unable to load driver."); } } @@ -1439,6 +1397,15 @@ exit: } } +void usbhInit(void) { + uint8_t i; + for (i = 0; i < sizeof_array(usbh_classdrivers_lookup); i++) { + if (usbh_classdrivers_lookup[i]->vmt->init) { + usbh_classdrivers_lookup[i]->vmt->init(); + } + } + usbh_lld_init(); +} #endif diff --git a/os/hal/src/usbh/TODO.txt b/os/hal/src/usbh/TODO.txt new file mode 100644 index 0000000..87269be --- /dev/null +++ b/os/hal/src/usbh/TODO.txt @@ -0,0 +1,21 @@ +In decreasing order of priority: + +Bugs: +- Synchronization on driver unload between usbhMainLoop and driver APIs + - MSD: ok + - AOA: not done + - HUB: ok + - FTDI: not done + - HID: ok + - UVC: not done + + +Enhancements: +- Way to return error from the load() functions in order to stop the enumeration process +- Event sources from the low-level driver, in order to know when to call usbhMainLoop (from the low-level driver and from the HUB driver status callback) +- Possibility of internal main loop +- Linked list for drivers for dynamic registration +- A way to automate matching (similar to linux) +- Hooks to override driver loading and to inform the user of problems +- for STM32 LLD: think of a way to prevent Bulk IN NAK interrupt flood. +- Integrate VBUS power switching functionality to the API. diff --git a/os/hal/src/usbh/hal_usbh_aoa.c b/os/hal/src/usbh/hal_usbh_aoa.c index 1fa49f8..85c3130 100644 --- a/os/hal/src/usbh/hal_usbh_aoa.c +++ b/os/hal/src/usbh/hal_usbh_aoa.c @@ -124,14 +124,16 @@ USBHAOADriver USBHAOAD[HAL_USBHAOA_MAX_INSTANCES]; static usbh_baseclassdriver_t *_aoa_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem); static void _aoa_unload(usbh_baseclassdriver_t *drv); +static void _aoa_init(void); static const usbh_classdriver_vmt_t class_driver_vmt = { + _aoa_init, _aoa_load, _aoa_unload }; const usbh_classdriverinfo_t usbhaoaClassDriverInfo = { - 0xff, 0xff, 0xff, "AOA", &class_driver_vmt + "AOA", &class_driver_vmt }; #if defined(HAL_USBHAOA_FILTER_CALLBACK) @@ -144,7 +146,7 @@ static usbh_baseclassdriver_t *_aoa_load(usbh_device_t *dev, const uint8_t *desc if (dev->devDesc.idVendor != AOA_GOOGLE_VID) { uint16_t protocol; - static const USBHAOAConfig config = { + static USBHAOAConfig config = { { HAL_USBHAOA_DEFAULT_MANUFACTURER, HAL_USBHAOA_DEFAULT_MODEL, @@ -221,15 +223,9 @@ static usbh_baseclassdriver_t *_aoa_load(usbh_device_t *dev, const uint8_t *desc return NULL; } - if ((rem < descriptor[0]) || (descriptor[1] != USBH_DT_INTERFACE)) - return NULL; - const usbh_interface_descriptor_t * const ifdesc = (const usbh_interface_descriptor_t *)descriptor; - - if ((ifdesc->bInterfaceClass != 0xff) - || (ifdesc->bInterfaceSubClass != 0xff) - || (ifdesc->bInterfaceProtocol != 0x00) - || (ifdesc->bNumEndpoints < 2)) { + if ((_usbh_match_descriptor(descriptor, rem, USBH_DT_INTERFACE, 0xFF, 0xFF, 0x00) != HAL_SUCCESS) + || (ifdesc->bNumEndpoints < 2)) { uerr("AOA: This IF is not the Accessory IF"); return NULL; } @@ -299,7 +295,6 @@ static void _aoa_unload(usbh_baseclassdriver_t *drv) { _stop_channelS(&aoap->channel); aoap->channel.state = USBHAOA_CHANNEL_STATE_STOP; aoap->state = USBHAOA_STATE_STOP; - osalOsRescheduleS(); osalSysUnlock(); } @@ -341,15 +336,15 @@ static size_t _write_timeout(USBHAOAChannel *aoacp, const uint8_t *bp, chDbgCheck(n > 0U); size_t w = 0; - chSysLock(); + osalSysLock(); while (true) { if (aoacp->state != USBHAOA_CHANNEL_STATE_READY) { - chSysUnlock(); + osalSysUnlock(); return w; } while (usbhURBIsBusy(&aoacp->oq_urb)) { if (chThdEnqueueTimeoutS(&aoacp->oq_waiting, timeout) != Q_OK) { - chSysUnlock(); + osalSysUnlock(); return w; } } @@ -357,30 +352,30 @@ static size_t _write_timeout(USBHAOAChannel *aoacp, const uint8_t *bp, *aoacp->oq_ptr++ = *bp++; if (--aoacp->oq_counter == 0) { _submitOutI(aoacp, 64); - chSchRescheduleS(); + osalOsRescheduleS(); } - chSysUnlock(); /* Gives a preemption chance in a controlled point.*/ + osalSysUnlock(); /* Gives a preemption chance in a controlled point.*/ w++; if (--n == 0U) return w; - chSysLock(); + osalSysLock(); } } static msg_t _put_timeout(USBHAOAChannel *aoacp, uint8_t b, systime_t timeout) { - chSysLock(); + osalSysLock(); if (aoacp->state != USBHAOA_CHANNEL_STATE_READY) { - chSysUnlock(); + osalSysUnlock(); return Q_RESET; } while (usbhURBIsBusy(&aoacp->oq_urb)) { msg_t msg = chThdEnqueueTimeoutS(&aoacp->oq_waiting, timeout); if (msg < Q_OK) { - chSysUnlock(); + osalSysUnlock(); return msg; } } @@ -388,9 +383,9 @@ static msg_t _put_timeout(USBHAOAChannel *aoacp, uint8_t b, systime_t timeout) { *aoacp->oq_ptr++ = b; if (--aoacp->oq_counter == 0) { _submitOutI(aoacp, 64); - chSchRescheduleS(); + osalOsRescheduleS(); } - chSysUnlock(); + osalSysUnlock(); return Q_OK; } @@ -439,41 +434,41 @@ static size_t _read_timeout(USBHAOAChannel *aoacp, uint8_t *bp, chDbgCheck(n > 0U); - chSysLock(); + osalSysLock(); while (true) { if (aoacp->state != USBHAOA_CHANNEL_STATE_READY) { - chSysUnlock(); + osalSysUnlock(); return r; } while (aoacp->iq_counter == 0) { if (!usbhURBIsBusy(&aoacp->iq_urb)) _submitInI(aoacp); if (chThdEnqueueTimeoutS(&aoacp->iq_waiting, timeout) != Q_OK) { - chSysUnlock(); + osalSysUnlock(); return r; } } *bp++ = *aoacp->iq_ptr++; if (--aoacp->iq_counter == 0) { _submitInI(aoacp); - chSchRescheduleS(); + osalOsRescheduleS(); } - chSysUnlock(); + osalSysUnlock(); r++; if (--n == 0U) return r; - chSysLock(); + osalSysLock(); } } static msg_t _get_timeout(USBHAOAChannel *aoacp, systime_t timeout) { uint8_t b; - chSysLock(); + osalSysLock(); if (aoacp->state != USBHAOA_CHANNEL_STATE_READY) { - chSysUnlock(); + osalSysUnlock(); return Q_RESET; } while (aoacp->iq_counter == 0) { @@ -481,16 +476,16 @@ static msg_t _get_timeout(USBHAOAChannel *aoacp, systime_t timeout) { _submitInI(aoacp); msg_t msg = chThdEnqueueTimeoutS(&aoacp->iq_waiting, timeout); if (msg < Q_OK) { - chSysUnlock(); + osalSysUnlock(); return msg; } } b = *aoacp->iq_ptr++; if (--aoacp->iq_counter == 0) { _submitInI(aoacp); - chSchRescheduleS(); + osalOsRescheduleS(); } - chSysUnlock(); + osalSysUnlock(); return (msg_t)b; } @@ -525,11 +520,12 @@ static void _stop_channelS(USBHAOAChannel *aoacp) { chThdDequeueAllI(&aoacp->oq_waiting, Q_RESET); chnAddFlagsI(aoacp, CHN_DISCONNECTED); aoacp->state = USBHAOA_CHANNEL_STATE_ACTIVE; + osalOsRescheduleS(); } static void _vt(void *p) { USBHAOAChannel *const aoacp = (USBHAOAChannel *)p; - chSysLockFromISR(); + osalSysLockFromISR(); uint32_t len = aoacp->oq_ptr - aoacp->oq_buff; if (len && !usbhURBIsBusy(&aoacp->oq_urb)) { _submitOutI(aoacp, len); @@ -538,7 +534,7 @@ static void _vt(void *p) { _submitInI(aoacp); } chVTSetI(&aoacp->vt, MS2ST(16), _vt, aoacp); - chSysUnlockFromISR(); + osalSysUnlockFromISR(); } void usbhaoaChannelStart(USBHAOADriver *aoap) { @@ -566,9 +562,7 @@ void usbhaoaChannelStart(USBHAOADriver *aoap) { aoacp->iq_counter = 0; aoacp->iq_ptr = aoacp->iq_buff; usbhEPOpen(&aoacp->epin); - osalSysLock(); - usbhURBSubmitI(&aoacp->iq_urb); - osalSysUnlock(); + usbhURBSubmit(&aoacp->iq_urb); chVTObjectInit(&aoacp->vt); chVTSet(&aoacp->vt, MS2ST(16), _vt, aoacp); @@ -583,7 +577,6 @@ void usbhaoaChannelStop(USBHAOADriver *aoap) { || (aoap->channel.state == USBHAOA_CHANNEL_STATE_READY)); osalSysLock(); _stop_channelS(&aoap->channel); - osalOsRescheduleS(); osalSysUnlock(); } @@ -658,7 +651,7 @@ static bool _send_string(usbh_device_t *dev, uint8_t index, const char *string) return HAL_SUCCESS; } -void usbhaoaObjectInit(USBHAOADriver *aoap) { +static void _object_init(USBHAOADriver *aoap) { osalDbgCheck(aoap != NULL); memset(aoap, 0, sizeof(*aoap)); aoap->info = &usbhaoaClassDriverInfo; @@ -668,10 +661,10 @@ void usbhaoaObjectInit(USBHAOADriver *aoap) { aoap->channel.state = USBHAOA_CHANNEL_STATE_STOP; } -void usbhaoaInit(void) { +static void _aoa_init(void) { uint8_t i; for (i = 0; i < HAL_USBHAOA_MAX_INSTANCES; i++) { - usbhaoaObjectInit(&USBHAOAD[i]); + _object_init(&USBHAOAD[i]); } } diff --git a/os/hal/src/usbh/hal_usbh_debug.c b/os/hal/src/usbh/hal_usbh_debug.c index 7c4ff7d..d32f1c6 100644 --- a/os/hal/src/usbh/hal_usbh_debug.c +++ b/os/hal/src/usbh/hal_usbh_debug.c @@ -106,17 +106,18 @@ static char *ftoa(char *p, double num, unsigned long precision, bool dot) { } #endif -static inline void _put(char c) { - input_queue_t *iqp = &USBH_DEBUG_USBHD.iq; - - if (iqIsFullI(iqp)) - return; - - iqp->q_counter++; +static inline void _wr(input_queue_t *iqp, char c) { *iqp->q_wrptr++ = c; if (iqp->q_wrptr >= iqp->q_top) iqp->q_wrptr = iqp->q_buffer; +} +static inline void _put(char c) { + input_queue_t *iqp = &USBH_DEBUG_USBHD.iq; + if (sizeof(USBH_DEBUG_USBHD.dbg_buff) - iqp->q_counter <= 1) + return; + iqp->q_counter++; + _wr(iqp, c); } int _dbg_printf(const char *fmt, va_list ap) { @@ -341,19 +342,39 @@ unsigned_common: } -static void _print_hdr(void) -{ +static systime_t first, last; +static bool ena; +static uint32_t hdr[2]; + +static void _build_hdr(void) { uint32_t hfnum = USBH_DEBUG_USBHD.otg->HFNUM; uint16_t hfir = USBH_DEBUG_USBHD.otg->HFIR; + last = osalOsGetSystemTimeX(); + if (ena) { + first = last; + } + + if (((hfnum & 0x3fff) == 0x3fff) && (hfir == (hfnum >> 16))) { + hdr[0] = 0xfeff; + hdr[1] = last - first; + ena = FALSE; + } else { + hdr[0] = 0xffff | (hfir << 16); + hdr[1] = hfnum; + ena = TRUE; + } +} - _put(0xff); - _put(0xff); - _put(hfir & 0xff); - _put(hfir >> 8); - _put(hfnum & 0xff); - _put((hfnum >> 8) & 0xff); - _put((hfnum >> 16) & 0xff); - _put((hfnum >> 24) & 0xff); +static void _print_hdr(void) +{ + _put(hdr[0] & 0xff); + _put((hdr[0] >> 8) & 0xff); + _put((hdr[0] >> 16) & 0xff); + _put((hdr[0] >> 24) & 0xff); + _put(hdr[1] & 0xff); + _put((hdr[1] >> 8) & 0xff); + _put((hdr[1] >> 16) & 0xff); + _put((hdr[1] >> 24) & 0xff); } void usbDbgPrintf(const char *fmt, ...) @@ -361,10 +382,16 @@ void usbDbgPrintf(const char *fmt, ...) va_list ap; va_start(ap, fmt); syssts_t sts = chSysGetStatusAndLockX(); - _print_hdr(); - _dbg_printf(fmt, ap); - _put(0); - chThdDequeueNextI(&USBH_DEBUG_USBHD.iq.q_waiting, Q_OK); + input_queue_t *iqp = &USBH_DEBUG_USBHD.iq; + int rem = sizeof(USBH_DEBUG_USBHD.dbg_buff) - iqp->q_counter; + if (rem >= 9) { + _build_hdr(); + _print_hdr(); + _dbg_printf(fmt, ap); + iqp->q_counter++; + _wr(iqp, 0); + chThdDequeueNextI(&USBH_DEBUG_USBHD.iq.q_waiting, Q_OK); + } chSysRestoreStatusX(sts); va_end(ap); } @@ -372,32 +399,28 @@ void usbDbgPrintf(const char *fmt, ...) void usbDbgPuts(const char *s) { - uint32_t buff[2] = { - 0xffff | (USBH_DEBUG_USBHD.otg->HFIR << 16), - USBH_DEBUG_USBHD.otg->HFNUM - }; - uint8_t *p = (uint8_t *)buff; + _build_hdr(); + uint8_t *p = (uint8_t *)hdr; uint8_t *top = p + 8; syssts_t sts = chSysGetStatusAndLockX(); input_queue_t *iqp = &USBH_DEBUG_USBHD.iq; int rem = sizeof(USBH_DEBUG_USBHD.dbg_buff) - iqp->q_counter; - while (rem) { - *iqp->q_wrptr++ = *p; - if (iqp->q_wrptr >= iqp->q_top) - iqp->q_wrptr = iqp->q_buffer; - rem--; - if (++p == top) break; - } - while (rem) { - *iqp->q_wrptr++ = *s; - if (iqp->q_wrptr >= iqp->q_top) - iqp->q_wrptr = iqp->q_buffer; - rem--; - if (!*s++) break; + if (rem >= 9) { + while (rem) { + _wr(iqp, *p); + if (++p == top) break; + } + rem -= 9; + while (rem && *s) { + _wr(iqp, *s); + rem--; + s++; + } + _wr(iqp, 0); + iqp->q_counter = sizeof(USBH_DEBUG_USBHD.dbg_buff) - rem; + chThdDequeueNextI(&USBH_DEBUG_USBHD.iq.q_waiting, Q_OK); } - iqp->q_counter = sizeof(USBH_DEBUG_USBHD.dbg_buff) - rem; - chThdDequeueNextI(&USBH_DEBUG_USBHD.iq.q_waiting, Q_OK); chSysRestoreStatusX(sts); } @@ -429,8 +452,8 @@ void usbDbgSystemHalted(void) { if (!((bool)((USBH_DEBUG_SD.oqueue.q_wrptr == USBH_DEBUG_SD.oqueue.q_rdptr) && (USBH_DEBUG_SD.oqueue.q_counter != 0U)))) break; USBH_DEBUG_SD.oqueue.q_counter++; - while (!(USART1->SR & USART_SR_TXE)); - USART1->DR = *USBH_DEBUG_SD.oqueue.q_rdptr++; + while (!(USBH_DEBUG_SD.usart->SR & USART_SR_TXE)); + USBH_DEBUG_SD.usart->DR = *USBH_DEBUG_SD.oqueue.q_rdptr++; if (USBH_DEBUG_SD.oqueue.q_rdptr >= USBH_DEBUG_SD.oqueue.q_top) { USBH_DEBUG_SD.oqueue.q_rdptr = USBH_DEBUG_SD.oqueue.q_buffer; } @@ -456,15 +479,15 @@ void usbDbgSystemHalted(void) { while (true) { c = _get(); if (c < 0) return; if (!c) { - while (!(USART1->SR & USART_SR_TXE)); - USART1->DR = '\r'; - while (!(USART1->SR & USART_SR_TXE)); - USART1->DR = '\n'; + while (!(USBH_DEBUG_SD.usart->SR & USART_SR_TXE)); + USBH_DEBUG_SD.usart->DR = '\r'; + while (!(USBH_DEBUG_SD.usart->SR & USART_SR_TXE)); + USBH_DEBUG_SD.usart->DR = '\n'; state = 0; break; } - while (!(USART1->SR & USART_SR_TXE)); - USART1->DR = c; + while (!(USBH_DEBUG_SD.usart->SR & USART_SR_TXE)); + USBH_DEBUG_SD.usart->DR = c; } } } @@ -483,8 +506,9 @@ static void usb_debug_thread(void *arg) { if (c == 0xff) state = 1; } else if (state == 1) { if (c == 0xff) state = 2; + else if (c == 0xfe) state = 3; else (state = 0); - } else { + } else if (state == 2) { uint16_t hfir; uint32_t hfnum; @@ -503,10 +527,26 @@ static void usb_debug_thread(void *arg) { uint32_t f = hfnum & 0xffff; uint32_t p = 1000 - ((hfnum >> 16) / (hfir / 1000)); - chprintf((BaseSequentialStream *)&USBH_DEBUG_SD, "%05d.%03d ", f, p); + chprintf((BaseSequentialStream *)&USBH_DEBUG_SD, "%05d.%03d ", f, p); + state = 4; + } else if (state == 3) { + uint32_t t; + c = iqGet(&host->iq); if (c < 0) goto reset; + c = iqGet(&host->iq); if (c < 0) goto reset; + + t = c; + c = iqGet(&host->iq); if (c < 0) goto reset; + t |= c << 8; + c = iqGet(&host->iq); if (c < 0) goto reset; + t |= c << 16; + c = iqGet(&host->iq); if (c < 0) goto reset; + t |= c << 24; + + chprintf((BaseSequentialStream *)&USBH_DEBUG_SD, "+%08d ", t); + state = 4; + } else { while (true) { - c = iqGet(&host->iq); if (c < 0) goto reset; if (!c) { sdPut(&USBH_DEBUG_SD, '\r'); sdPut(&USBH_DEBUG_SD, '\n'); @@ -514,6 +554,7 @@ static void usb_debug_thread(void *arg) { break; } sdPut(&USBH_DEBUG_SD, (uint8_t)c); + c = iqGet(&host->iq); if (c < 0) goto reset; } } diff --git a/os/hal/src/usbh/hal_usbh_ftdi.c b/os/hal/src/usbh/hal_usbh_ftdi.c index ce96958..6fb556d 100644 --- a/os/hal/src/usbh/hal_usbh_ftdi.c +++ b/os/hal/src/usbh/hal_usbh_ftdi.c @@ -27,9 +27,6 @@ #include "usbh/dev/ftdi.h" #include "usbh/internal.h" -//#pragma GCC optimize("Og") - - #if USBHFTDI_DEBUG_ENABLE_TRACE #define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) #define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__) @@ -62,22 +59,25 @@ #define uerr(f, ...) do {} while(0) #endif +static void _ftdip_object_init(USBHFTDIPortDriver *ftdipp); /*===========================================================================*/ /* USB Class driver loader for FTDI */ /*===========================================================================*/ USBHFTDIDriver USBHFTDID[HAL_USBHFTDI_MAX_INSTANCES]; +static void _ftdi_init(void); static usbh_baseclassdriver_t *_ftdi_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem); static void _ftdi_unload(usbh_baseclassdriver_t *drv); static const usbh_classdriver_vmt_t class_driver_vmt = { + _ftdi_init, _ftdi_load, _ftdi_unload }; const usbh_classdriverinfo_t usbhftdiClassDriverInfo = { - 0xff, 0xff, 0xff, "FTDI", &class_driver_vmt + "FTDI", &class_driver_vmt }; static USBHFTDIPortDriver *_find_port(void) { @@ -93,10 +93,8 @@ static usbh_baseclassdriver_t *_ftdi_load(usbh_device_t *dev, const uint8_t *des int i; USBHFTDIDriver *ftdip; - if (dev->devDesc.idVendor != 0x0403) { - uerr("FTDI: Unrecognized VID"); + if (_usbh_match_vid_pid(dev, 0x0403, -1) != HAL_SUCCESS) return NULL; - } switch (dev->devDesc.idProduct) { case 0x6001: @@ -111,7 +109,8 @@ static usbh_baseclassdriver_t *_ftdi_load(usbh_device_t *dev, const uint8_t *des return NULL; } - if ((rem < descriptor[0]) || (descriptor[1] != USBH_DT_INTERFACE)) + if (_usbh_match_descriptor(descriptor, rem, USBH_DT_INTERFACE, + 0xff, 0xff, 0xff) != HAL_SUCCESS) return NULL; if (((const usbh_interface_descriptor_t *)descriptor)->bInterfaceNumber != 0) { @@ -220,7 +219,6 @@ static void _ftdi_unload(usbh_baseclassdriver_t *drv) { while (ftdipp) { osalSysLock(); _stopS(ftdipp); - osalOsRescheduleS(); osalSysUnlock(); ftdipp = ftdipp->next; } @@ -229,7 +227,7 @@ static void _ftdi_unload(usbh_baseclassdriver_t *drv) { osalSysLock(); while (ftdipp) { USBHFTDIPortDriver *next = ftdipp->next; - usbhftdipObjectInit(ftdipp); + _ftdip_object_init(ftdipp); ftdipp = next; } osalSysUnlock(); @@ -417,7 +415,7 @@ static void _out_cb(usbh_urb_t *urb) { return; case USBH_URBSTATUS_DISCONNECTED: uwarn("FTDI: URB OUT disconnected"); - chThdDequeueNextI(&ftdipp->oq_waiting, Q_RESET); + chThdDequeueAllI(&ftdipp->oq_waiting, Q_RESET); return; default: uerrf("FTDI: URB OUT status unexpected = %d", urb->status); @@ -432,15 +430,15 @@ static size_t _write_timeout(USBHFTDIPortDriver *ftdipp, const uint8_t *bp, chDbgCheck(n > 0U); size_t w = 0; - chSysLock(); + osalSysLock(); while (true) { if (ftdipp->state != USBHFTDIP_STATE_READY) { - chSysUnlock(); + osalSysUnlock(); return w; } while (usbhURBIsBusy(&ftdipp->oq_urb)) { if (chThdEnqueueTimeoutS(&ftdipp->oq_waiting, timeout) != Q_OK) { - chSysUnlock(); + osalSysUnlock(); return w; } } @@ -448,30 +446,30 @@ static size_t _write_timeout(USBHFTDIPortDriver *ftdipp, const uint8_t *bp, *ftdipp->oq_ptr++ = *bp++; if (--ftdipp->oq_counter == 0) { _submitOutI(ftdipp, 64); - chSchRescheduleS(); + osalOsRescheduleS(); } - chSysUnlock(); /* Gives a preemption chance in a controlled point.*/ + osalSysUnlock(); /* Gives a preemption chance in a controlled point.*/ w++; if (--n == 0U) return w; - chSysLock(); + osalSysLock(); } } static msg_t _put_timeout(USBHFTDIPortDriver *ftdipp, uint8_t b, systime_t timeout) { - chSysLock(); + osalSysLock(); if (ftdipp->state != USBHFTDIP_STATE_READY) { - chSysUnlock(); + osalSysUnlock(); return Q_RESET; } while (usbhURBIsBusy(&ftdipp->oq_urb)) { msg_t msg = chThdEnqueueTimeoutS(&ftdipp->oq_waiting, timeout); if (msg < Q_OK) { - chSysUnlock(); + osalSysUnlock(); return msg; } } @@ -479,9 +477,9 @@ static msg_t _put_timeout(USBHFTDIPortDriver *ftdipp, uint8_t b, systime_t timeo *ftdipp->oq_ptr++ = b; if (--ftdipp->oq_counter == 0) { _submitOutI(ftdipp, 64); - chSchRescheduleS(); + osalOsRescheduleS(); } - chSysUnlock(); + osalSysUnlock(); return Q_OK; } @@ -518,12 +516,12 @@ static void _in_cb(usbh_urb_t *urb) { udbgf("FTDI: URB IN no data, status=%02x %02x", ((uint8_t *)urb->buff)[0], ((uint8_t *)urb->buff)[1]); - return; + // return; } break; case USBH_URBSTATUS_DISCONNECTED: uwarn("FTDI: URB IN disconnected"); - chThdDequeueNextI(&ftdipp->iq_waiting, Q_RESET); + chThdDequeueAllI(&ftdipp->iq_waiting, Q_RESET); return; default: uerrf("FTDI: URB IN status unexpected = %d", urb->status); @@ -538,41 +536,41 @@ static size_t _read_timeout(USBHFTDIPortDriver *ftdipp, uint8_t *bp, chDbgCheck(n > 0U); - chSysLock(); + osalSysLock(); while (true) { if (ftdipp->state != USBHFTDIP_STATE_READY) { - chSysUnlock(); + osalSysUnlock(); return r; } while (ftdipp->iq_counter == 0) { if (!usbhURBIsBusy(&ftdipp->iq_urb)) _submitInI(ftdipp); if (chThdEnqueueTimeoutS(&ftdipp->iq_waiting, timeout) != Q_OK) { - chSysUnlock(); + osalSysUnlock(); return r; } } *bp++ = *ftdipp->iq_ptr++; if (--ftdipp->iq_counter == 0) { _submitInI(ftdipp); - chSchRescheduleS(); + osalOsRescheduleS(); } - chSysUnlock(); + osalSysUnlock(); r++; if (--n == 0U) return r; - chSysLock(); + osalSysLock(); } } static msg_t _get_timeout(USBHFTDIPortDriver *ftdipp, systime_t timeout) { uint8_t b; - chSysLock(); + osalSysLock(); if (ftdipp->state != USBHFTDIP_STATE_READY) { - chSysUnlock(); + osalSysUnlock(); return Q_RESET; } while (ftdipp->iq_counter == 0) { @@ -580,16 +578,16 @@ static msg_t _get_timeout(USBHFTDIPortDriver *ftdipp, systime_t timeout) { _submitInI(ftdipp); msg_t msg = chThdEnqueueTimeoutS(&ftdipp->iq_waiting, timeout); if (msg < Q_OK) { - chSysUnlock(); + osalSysUnlock(); return msg; } } b = *ftdipp->iq_ptr++; if (--ftdipp->iq_counter == 0) { _submitInI(ftdipp); - chSchRescheduleS(); + osalOsRescheduleS(); } - chSysUnlock(); + osalSysUnlock(); return (msg_t)b; } @@ -604,7 +602,7 @@ static size_t _read(USBHFTDIPortDriver *ftdipp, uint8_t *bp, size_t n) { static void _vt(void *p) { USBHFTDIPortDriver *const ftdipp = (USBHFTDIPortDriver *)p; - chSysLockFromISR(); + osalSysLockFromISR(); uint32_t len = ftdipp->oq_ptr - ftdipp->oq_buff; if (len && !usbhURBIsBusy(&ftdipp->oq_urb)) { _submitOutI(ftdipp, len); @@ -613,7 +611,7 @@ static void _vt(void *p) { _submitInI(ftdipp); } chVTSetI(&ftdipp->vt, MS2ST(16), _vt, ftdipp); - chSysUnlockFromISR(); + osalSysUnlockFromISR(); } static const struct FTDIPortDriverVMT async_channel_vmt = { @@ -637,6 +635,7 @@ static void _stopS(USBHFTDIPortDriver *ftdipp) { chThdDequeueAllI(&ftdipp->iq_waiting, Q_RESET); chThdDequeueAllI(&ftdipp->oq_waiting, Q_RESET); ftdipp->state = USBHFTDIP_STATE_ACTIVE; + osalOsRescheduleS(); } void usbhftdipStop(USBHFTDIPortDriver *ftdipp) { @@ -647,7 +646,6 @@ void usbhftdipStop(USBHFTDIPortDriver *ftdipp) { chMtxLockS(&ftdipp->ftdip->mtx); _stopS(ftdipp); chMtxUnlockS(&ftdipp->ftdip->mtx); - osalOsRescheduleS(); osalSysUnlock(); } @@ -689,9 +687,7 @@ void usbhftdipStart(USBHFTDIPortDriver *ftdipp, const USBHFTDIPortConfig *config ftdipp->iq_counter = 0; ftdipp->iq_ptr = ftdipp->iq_buff; usbhEPOpen(&ftdipp->epin); - osalSysLock(); - usbhURBSubmitI(&ftdipp->iq_urb); - osalSysUnlock(); + usbhURBSubmit(&ftdipp->iq_urb); chVTObjectInit(&ftdipp->vt); chVTSet(&ftdipp->vt, MS2ST(16), _vt, ftdipp); @@ -700,27 +696,27 @@ void usbhftdipStart(USBHFTDIPortDriver *ftdipp, const USBHFTDIPortConfig *config osalMutexUnlock(&ftdipp->ftdip->mtx); } -void usbhftdiObjectInit(USBHFTDIDriver *ftdip) { +static void _ftdi_object_init(USBHFTDIDriver *ftdip) { osalDbgCheck(ftdip != NULL); memset(ftdip, 0, sizeof(*ftdip)); ftdip->info = &usbhftdiClassDriverInfo; osalMutexObjectInit(&ftdip->mtx); } -void usbhftdipObjectInit(USBHFTDIPortDriver *ftdipp) { +static void _ftdip_object_init(USBHFTDIPortDriver *ftdipp) { osalDbgCheck(ftdipp != NULL); memset(ftdipp, 0, sizeof(*ftdipp)); ftdipp->vmt = &async_channel_vmt; ftdipp->state = USBHFTDIP_STATE_STOP; } -void usbhftdiInit(void) { +static void _ftdi_init(void) { uint8_t i; for (i = 0; i < HAL_USBHFTDI_MAX_INSTANCES; i++) { - usbhftdiObjectInit(&USBHFTDID[i]); + _ftdi_object_init(&USBHFTDID[i]); } for (i = 0; i < HAL_USBHFTDI_MAX_PORTS; i++) { - usbhftdipObjectInit(&FTDIPD[i]); + _ftdip_object_init(&FTDIPD[i]); } } diff --git a/os/hal/src/usbh/hal_usbh_hid.c b/os/hal/src/usbh/hal_usbh_hid.c index e98dff7..2b2c5ce 100644 --- a/os/hal/src/usbh/hal_usbh_hid.c +++ b/os/hal/src/usbh/hal_usbh_hid.c @@ -69,28 +69,32 @@ #define USBH_HID_REQ_SET_PROTOCOL 0x0B /*===========================================================================*/ -/* USB Class driver loader for MSD */ +/* USB Class driver loader for HID */ /*===========================================================================*/ USBHHIDDriver USBHHIDD[HAL_USBHHID_MAX_INSTANCES]; +static void _hid_init(void); static usbh_baseclassdriver_t *_hid_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem); static void _hid_unload(usbh_baseclassdriver_t *drv); +static void _stop_locked(USBHHIDDriver *hidp); static const usbh_classdriver_vmt_t class_driver_vmt = { + _hid_init, _hid_load, _hid_unload }; const usbh_classdriverinfo_t usbhhidClassDriverInfo = { - 0x03, -1, -1, "HID", &class_driver_vmt + "HID", &class_driver_vmt }; static usbh_baseclassdriver_t *_hid_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem) { int i; USBHHIDDriver *hidp; - if ((rem < descriptor[0]) || (descriptor[1] != USBH_DT_INTERFACE)) + if (_usbh_match_descriptor(descriptor, rem, USBH_DT_INTERFACE, + 0x03, -1, -1) != HAL_SUCCESS) return NULL; const usbh_interface_descriptor_t * const ifdesc = (const usbh_interface_descriptor_t *)descriptor; @@ -180,7 +184,11 @@ deinit: } static void _hid_unload(usbh_baseclassdriver_t *drv) { - (void)drv; + USBHHIDDriver *const hidp = (USBHHIDDriver *)drv; + chSemWait(&hidp->sem); + _stop_locked(hidp); + hidp->state = USBHHID_STATE_STOP; + chSemSignal(&hidp->sem); } static void _in_cb(usbh_urb_t *urb) { @@ -209,17 +217,22 @@ static void _in_cb(usbh_urb_t *urb) { void usbhhidStart(USBHHIDDriver *hidp, const USBHHIDConfig *cfg) { osalDbgCheck(hidp && cfg); osalDbgCheck(cfg->report_buffer && (cfg->protocol <= USBHHID_PROTOCOL_REPORT)); - osalDbgCheck((hidp->state == USBHHID_STATE_ACTIVE) - || (hidp->state == USBHHID_STATE_READY)); - if (hidp->state == USBHHID_STATE_READY) + chSemWait(&hidp->sem); + if (hidp->state == USBHHID_STATE_READY) { + chSemSignal(&hidp->sem); return; + } + osalDbgCheck(hidp->state == USBHHID_STATE_ACTIVE); hidp->config = cfg; /* init the URBs */ + uint32_t report_len = hidp->epin.wMaxPacketSize; + if (report_len > cfg->report_len) + report_len = cfg->report_len; usbhURBObjectInit(&hidp->in_urb, &hidp->epin, _in_cb, hidp, - cfg->report_buffer, cfg->report_len); + cfg->report_buffer, report_len); /* open the int IN/OUT endpoints */ usbhEPOpen(&hidp->epin); @@ -231,29 +244,31 @@ void usbhhidStart(USBHHIDDriver *hidp, const USBHHIDConfig *cfg) { usbhhidSetProtocol(hidp, cfg->protocol); - osalSysLock(); - usbhURBSubmitI(&hidp->in_urb); - osalSysUnlock(); + usbhURBSubmit(&hidp->in_urb); hidp->state = USBHHID_STATE_READY; + chSemSignal(&hidp->sem); } -void usbhhidStop(USBHHIDDriver *hidp) { - osalDbgCheck((hidp->state == USBHHID_STATE_ACTIVE) - || (hidp->state == USBHHID_STATE_READY)); - - if (hidp->state != USBHHID_STATE_READY) +static void _stop_locked(USBHHIDDriver *hidp) { + if (hidp->state == USBHHID_STATE_ACTIVE) return; - osalSysLock(); - usbhEPCloseS(&hidp->epin); + osalDbgCheck(hidp->state == USBHHID_STATE_READY); + + usbhEPClose(&hidp->epin); #if HAL_USBHHID_USE_INTERRUPT_OUT if (hidp->epout.status != USBH_EPSTATUS_UNINITIALIZED) { - usbhEPCloseS(&hidp->epout); + usbhEPClose(&hidp->epout); } #endif hidp->state = USBHHID_STATE_ACTIVE; - osalSysUnlock(); +} + +void usbhhidStop(USBHHIDDriver *hidp) { + chSemWait(&hidp->sem); + _stop_locked(hidp); + chSemSignal(&hidp->sem); } usbh_urbstatus_t usbhhidGetReport(USBHHIDDriver *hidp, @@ -305,17 +320,18 @@ usbh_urbstatus_t usbhhidSetProtocol(USBHHIDDriver *hidp, uint8_t protocol) { protocol, hidp->ifnum, 0, NULL); } -void usbhhidObjectInit(USBHHIDDriver *hidp) { +static void _hid_object_init(USBHHIDDriver *hidp) { osalDbgCheck(hidp != NULL); memset(hidp, 0, sizeof(*hidp)); hidp->info = &usbhhidClassDriverInfo; hidp->state = USBHHID_STATE_STOP; + chSemObjectInit(&hidp->sem, 1); } -void usbhhidInit(void) { +static void _hid_init(void) { uint8_t i; for (i = 0; i < HAL_USBHHID_MAX_INSTANCES; i++) { - usbhhidObjectInit(&USBHHIDD[i]); + _hid_object_init(&USBHHIDD[i]); } } diff --git a/os/hal/src/usbh/hal_usbh_hub.c b/os/hal/src/usbh/hal_usbh_hub.c index 3a84175..6a83c66 100644 --- a/os/hal/src/usbh/hal_usbh_hub.c +++ b/os/hal/src/usbh/hal_usbh_hub.c @@ -63,14 +63,17 @@ USBHHubDriver USBHHUBD[HAL_USBHHUB_MAX_INSTANCES]; static usbh_port_t USBHPorts[HAL_USBHHUB_MAX_PORTS]; -static usbh_baseclassdriver_t *hub_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem); -static void hub_unload(usbh_baseclassdriver_t *drv); +static void _hub_init(void); +static usbh_baseclassdriver_t *_hub_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem); +static void _hub_unload(usbh_baseclassdriver_t *drv); static const usbh_classdriver_vmt_t usbhhubClassDriverVMT = { - hub_load, - hub_unload + _hub_init, + _hub_load, + _hub_unload }; + const usbh_classdriverinfo_t usbhhubClassDriverInfo = { - 0x09, 0x00, -1, "HUB", &usbhhubClassDriverVMT + "HUB", &usbhhubClassDriverVMT }; @@ -104,7 +107,7 @@ static void _urb_complete(usbh_urb_t *urb) { case USBH_URBSTATUS_TIMEOUT: /* the device NAKed */ udbg("HUB: no info"); - hubdp->statuschange = 0; + //hubdp->statuschange = 0; break; case USBH_URBSTATUS_OK: { uint8_t len = hubdp->hubDesc.bNbrPorts / 8 + 1; @@ -137,16 +140,14 @@ static void _urb_complete(usbh_urb_t *urb) { usbhURBSubmitI(urb); } -static usbh_baseclassdriver_t *hub_load(usbh_device_t *dev, +static usbh_baseclassdriver_t *_hub_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem) { int i; USBHHubDriver *hubdp; - if ((rem < descriptor[0]) || (descriptor[1] != USBH_DT_DEVICE)) - return NULL; - - if (dev->devDesc.bDeviceProtocol != 0) + if (_usbh_match_descriptor(descriptor, rem, USBH_DT_DEVICE, + 0x09, 0x00, 0x00) != HAL_SUCCESS) return NULL; generic_iterator_t iep, icfg; @@ -158,12 +159,10 @@ static usbh_baseclassdriver_t *hub_load(usbh_device_t *dev, if_iter_init(&iif, &icfg); if (!iif.valid) return NULL; - const usbh_interface_descriptor_t *const ifdesc = if_get(&iif); - if ((ifdesc->bInterfaceClass != 0x09) - || (ifdesc->bInterfaceSubClass != 0x00) - || (ifdesc->bInterfaceProtocol != 0x00)) { + + if (_usbh_match_descriptor(iif.curr, iif.rem, USBH_DT_INTERFACE, + 0x09, 0x00, 0x00) != HAL_SUCCESS) return NULL; - } ep_iter_init(&iep, &iif); if (!iep.valid) @@ -253,22 +252,18 @@ alloc_ok: _urb_complete, hubdp, hubdp->scbuff, (hubdesc->bNbrPorts + 8) / 8); - osalSysLock(); - usbhURBSubmitI(&hubdp->urb); - osalOsRescheduleS(); - osalSysUnlock(); + usbhURBSubmit(&hubdp->urb); + hubdp->dev = NULL; return (usbh_baseclassdriver_t *)hubdp; } -static void hub_unload(usbh_baseclassdriver_t *drv) { +static void _hub_unload(usbh_baseclassdriver_t *drv) { osalDbgCheck(drv != NULL); USBHHubDriver *const hubdp = (USBHHubDriver *)drv; /* close the status change endpoint (this cancels ongoing URBs) */ - osalSysLock(); - usbhEPCloseS(&hubdp->epint); - osalSysUnlock(); + usbhEPClose(&hubdp->epint); /* de-alloc ports and unload drivers */ usbh_port_t *port = hubdp->ports; @@ -283,16 +278,16 @@ static void hub_unload(usbh_baseclassdriver_t *drv) { } -void usbhhubObjectInit(USBHHubDriver *hubdp) { +static void _object_init(USBHHubDriver *hubdp) { osalDbgCheck(hubdp != NULL); memset(hubdp, 0, sizeof(*hubdp)); hubdp->info = &usbhhubClassDriverInfo; } -void usbhhubInit(void) { +static void _hub_init(void) { uint8_t i; for (i = 0; i < HAL_USBHHUB_MAX_INSTANCES; i++) { - usbhhubObjectInit(&USBHHUBD[i]); + _object_init(&USBHHUBD[i]); } } diff --git a/os/hal/src/usbh/hal_usbh_msd.c b/os/hal/src/usbh/hal_usbh_msd.c index b564e8e..069c47b 100644 --- a/os/hal/src/usbh/hal_usbh_msd.c +++ b/os/hal/src/usbh/hal_usbh_msd.c @@ -27,9 +27,6 @@ #include "usbh/dev/msd.h" #include "usbh/internal.h" -//#pragma GCC optimize("Og") - - #if USBHMSD_DEBUG_ENABLE_TRACE #define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) #define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__) @@ -62,26 +59,39 @@ #define uerr(f, ...) do {} while(0) #endif - - - +static void _lun_object_deinit(USBHMassStorageLUNDriver *lunp); /*===========================================================================*/ /* USB Class driver loader for MSD */ /*===========================================================================*/ -USBHMassStorageDriver USBHMSD[HAL_USBHMSD_MAX_INSTANCES]; +struct USBHMassStorageDriver { + /* inherited from abstract class driver */ + _usbh_base_classdriver_data + usbh_ep_t epin; + usbh_ep_t epout; + uint8_t ifnum; + uint8_t max_lun; + uint32_t tag; + + USBHMassStorageLUNDriver *luns; +}; + +static USBHMassStorageDriver USBHMSD[HAL_USBHMSD_MAX_INSTANCES]; + +static void _msd_init(void); static usbh_baseclassdriver_t *_msd_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem); static void _msd_unload(usbh_baseclassdriver_t *drv); static const usbh_classdriver_vmt_t class_driver_vmt = { + _msd_init, _msd_load, _msd_unload }; const usbh_classdriverinfo_t usbhmsdClassDriverInfo = { - 0x08, 0x06, 0x50, "MSD", &class_driver_vmt + "MSD", &class_driver_vmt }; #define MSD_REQ_RESET 0xFF @@ -93,15 +103,14 @@ static usbh_baseclassdriver_t *_msd_load(usbh_device_t *dev, const uint8_t *desc uint8_t luns; usbh_urbstatus_t stat; - if ((rem < descriptor[0]) || (descriptor[1] != USBH_DT_INTERFACE)) + if (_usbh_match_descriptor(descriptor, rem, USBH_DT_INTERFACE, + 0x08, 0x06, 0x50) != HAL_SUCCESS) return NULL; const usbh_interface_descriptor_t * const ifdesc = (const usbh_interface_descriptor_t *)descriptor; if ((ifdesc->bAlternateSetting != 0) - || (ifdesc->bNumEndpoints < 2) - || (ifdesc->bInterfaceSubClass != 0x06) - || (ifdesc->bInterfaceProtocol != 0x50)) { + || (ifdesc->bNumEndpoints < 2)) { return NULL; } @@ -187,15 +196,7 @@ alloc_ok: MSBLKD[i].next = msdp->luns; msdp->luns = &MSBLKD[i]; MSBLKD[i].msdp = msdp; - - osalSysLock(); - MSBLKD[i].state = BLK_ACTIVE; /* transition directly to active, instead of BLK_STOP */ - osalSysUnlock(); - - /* connect the LUN (TODO: review if it's best to leave the LUN disconnected) */ - msdp->dev = dev; - usbhmsdLUNConnect(&MSBLKD[i]); - msdp->dev = NULL; + MSBLKD[i].state = BLK_ACTIVE; luns--; } } @@ -212,25 +213,15 @@ static void _msd_unload(usbh_baseclassdriver_t *drv) { USBHMassStorageDriver *const msdp = (USBHMassStorageDriver *)drv; USBHMassStorageLUNDriver *lunp = msdp->luns; - osalMutexLock(&msdp->mtx); - osalSysLock(); - usbhEPCloseS(&msdp->epin); - usbhEPCloseS(&msdp->epout); + /* disconnect all LUNs */ while (lunp) { - lunp->state = BLK_STOP; + usbhmsdLUNDisconnect(lunp); + _lun_object_deinit(lunp); lunp = lunp->next; } - osalSysUnlock(); - osalMutexUnlock(&msdp->mtx); - /* now that the LUNs are idle, deinit them */ - lunp = msdp->luns; - osalSysLock(); - while (lunp) { - usbhmsdLUNObjectInit(lunp); - lunp = lunp->next; - } - osalSysUnlock(); + usbhEPClose(&msdp->epin); + usbhEPClose(&msdp->epout); } @@ -238,8 +229,6 @@ static void _msd_unload(usbh_baseclassdriver_t *drv) { /* MSD Class driver operations (Bulk-Only transport) */ /*===========================================================================*/ - - /* USB Bulk Only Transport SCSI Command block wrapper */ typedef PACKED_STRUCT { uint32_t dCBWSignature; @@ -704,11 +693,22 @@ static const struct USBHMassStorageDriverVMT blk_vmt = { (bool (*)(void *, BlockDeviceInfo *))usbhmsdLUNGetInfo }; -void usbhmsdLUNObjectInit(USBHMassStorageLUNDriver *lunp) { +static void _lun_object_deinit(USBHMassStorageLUNDriver *lunp) { + osalDbgCheck(lunp != NULL); + chSemWait(&lunp->sem); + lunp->msdp = NULL; + lunp->next = NULL; + memset(&lunp->info, 0, sizeof(lunp->info)); + lunp->state = BLK_STOP; + chSemSignal(&lunp->sem); +} + +static void _lun_object_init(USBHMassStorageLUNDriver *lunp) { osalDbgCheck(lunp != NULL); memset(lunp, 0, sizeof(*lunp)); lunp->vmt = &blk_vmt; lunp->state = BLK_STOP; + chSemObjectInit(&lunp->sem, 1); /* Unnecessary because of the memset: lunp->msdp = NULL; lunp->next = NULL; @@ -716,45 +716,18 @@ void usbhmsdLUNObjectInit(USBHMassStorageLUNDriver *lunp) { */ } -void usbhmsdLUNStart(USBHMassStorageLUNDriver *lunp) { - osalDbgCheck(lunp != NULL); - osalSysLock(); - osalDbgAssert((lunp->state == BLK_STOP) || (lunp->state == BLK_ACTIVE), - "invalid state"); - //TODO: complete - //lunp->state = BLK_ACTIVE; - osalSysUnlock(); -} - -void usbhmsdLUNStop(USBHMassStorageLUNDriver *lunp) { - osalDbgCheck(lunp != NULL); - osalSysLock(); - osalDbgAssert((lunp->state == BLK_STOP) || (lunp->state == BLK_ACTIVE), - "invalid state"); - //TODO: complete - //lunp->state = BLK_STOP; - osalSysUnlock(); -} - bool usbhmsdLUNConnect(USBHMassStorageLUNDriver *lunp) { - USBHMassStorageDriver *const msdp = lunp->msdp; + osalDbgCheck(lunp != NULL); + osalDbgCheck(lunp->msdp != NULL); msd_result_t res; - osalDbgCheck(msdp != NULL); - osalSysLock(); - //osalDbgAssert((lunp->state == BLK_ACTIVE) || (lunp->state == BLK_READY), - // "invalid state"); + chSemWait(&lunp->sem); + osalDbgAssert((lunp->state == BLK_READY) || (lunp->state == BLK_ACTIVE), "invalid state"); if (lunp->state == BLK_READY) { - osalSysUnlock(); + chSemSignal(&lunp->sem); return HAL_SUCCESS; - } else if (lunp->state != BLK_ACTIVE) { - osalSysUnlock(); - return HAL_FAILED; } lunp->state = BLK_CONNECTING; - osalSysUnlock(); - - osalMutexLock(&msdp->mtx); { USBH_DEFINE_BUFFER(scsi_inquiry_response_t inq); @@ -820,41 +793,34 @@ bool usbhmsdLUNConnect(USBHMassStorageLUNDriver *lunp) { (uint32_t)(((uint64_t)lunp->info.blk_size * lunp->info.blk_num) / (1024UL * 1024UL))); uinfo("MSD Connected."); - - osalMutexUnlock(&msdp->mtx); - osalSysLock(); lunp->state = BLK_READY; - osalSysUnlock(); - + chSemSignal(&lunp->sem); return HAL_SUCCESS; /* Connection failed, state reset to BLK_ACTIVE.*/ failed: - osalMutexUnlock(&msdp->mtx); - osalSysLock(); + uinfo("MSD Connect failed."); lunp->state = BLK_ACTIVE; - osalSysUnlock(); + chSemSignal(&lunp->sem); return HAL_FAILED; } - bool usbhmsdLUNDisconnect(USBHMassStorageLUNDriver *lunp) { osalDbgCheck(lunp != NULL); - osalSysLock(); - osalDbgAssert((lunp->state == BLK_ACTIVE) || (lunp->state == BLK_READY), - "invalid state"); + + chSemWait(&lunp->sem); + osalDbgAssert((lunp->state == BLK_READY) || (lunp->state == BLK_ACTIVE), "invalid state"); if (lunp->state == BLK_ACTIVE) { - osalSysUnlock(); + chSemSignal(&lunp->sem); return HAL_SUCCESS; } lunp->state = BLK_DISCONNECTING; - osalSysUnlock(); - //TODO: complete + //TODO: complete: sync, etc. - osalSysLock(); lunp->state = BLK_ACTIVE; - osalSysUnlock(); + chSemSignal(&lunp->sem); + return HAL_SUCCESS; } @@ -867,15 +833,13 @@ bool usbhmsdLUNRead(USBHMassStorageLUNDriver *lunp, uint32_t startblk, msd_result_t res; uint32_t actual_len; - osalSysLock(); + chSemWait(&lunp->sem); if (lunp->state != BLK_READY) { - osalSysUnlock(); + chSemSignal(&lunp->sem); return ret; } lunp->state = BLK_READING; - osalSysUnlock(); - osalMutexLock(&lunp->msdp->mtx); while (n) { if (n > 0xffff) { blocks = 0xffff; @@ -900,15 +864,8 @@ bool usbhmsdLUNRead(USBHMassStorageLUNDriver *lunp, uint32_t startblk, ret = HAL_SUCCESS; exit: - osalMutexUnlock(&lunp->msdp->mtx); - osalSysLock(); - if (lunp->state == BLK_READING) { - lunp->state = BLK_READY; - } else { - osalDbgCheck(lunp->state == BLK_STOP); - uwarn("MSD: State = BLK_STOP"); - } - osalSysUnlock(); + lunp->state = BLK_READY; + chSemSignal(&lunp->sem); return ret; } @@ -921,15 +878,13 @@ bool usbhmsdLUNWrite(USBHMassStorageLUNDriver *lunp, uint32_t startblk, msd_result_t res; uint32_t actual_len; - osalSysLock(); + chSemWait(&lunp->sem); if (lunp->state != BLK_READY) { - osalSysUnlock(); + chSemSignal(&lunp->sem); return ret; } lunp->state = BLK_WRITING; - osalSysUnlock(); - osalMutexLock(&lunp->msdp->mtx); while (n) { if (n > 0xffff) { blocks = 0xffff; @@ -954,15 +909,8 @@ bool usbhmsdLUNWrite(USBHMassStorageLUNDriver *lunp, uint32_t startblk, ret = HAL_SUCCESS; exit: - osalMutexUnlock(&lunp->msdp->mtx); - osalSysLock(); - if (lunp->state == BLK_WRITING) { - lunp->state = BLK_READY; - } else { - osalDbgCheck(lunp->state == BLK_STOP); - uwarn("MSD: State = BLK_STOP"); - } - osalSysUnlock(); + lunp->state = BLK_READY; + chSemSignal(&lunp->sem); return ret; } @@ -976,38 +924,41 @@ bool usbhmsdLUNSync(USBHMassStorageLUNDriver *lunp) { bool usbhmsdLUNGetInfo(USBHMassStorageLUNDriver *lunp, BlockDeviceInfo *bdip) { osalDbgCheck(lunp != NULL); osalDbgCheck(bdip != NULL); - *bdip = lunp->info; - return HAL_SUCCESS; + + osalSysLock(); + if (lunp->state >= BLK_READY) { + *bdip = lunp->info; + osalSysUnlock(); + return HAL_SUCCESS; + } + osalSysUnlock(); + return HAL_FAILED; } bool usbhmsdLUNIsInserted(USBHMassStorageLUNDriver *lunp) { osalDbgCheck(lunp != NULL); - blkstate_t state; - osalSysLock(); - state = lunp->state; - osalSysUnlock(); - return (state >= BLK_ACTIVE); + return (lunp->state >= BLK_ACTIVE); } bool usbhmsdLUNIsProtected(USBHMassStorageLUNDriver *lunp) { osalDbgCheck(lunp != NULL); + //TODO: Implement return FALSE; } -void usbhmsdObjectInit(USBHMassStorageDriver *msdp) { +static void _msd_object_init(USBHMassStorageDriver *msdp) { osalDbgCheck(msdp != NULL); memset(msdp, 0, sizeof(*msdp)); msdp->info = &usbhmsdClassDriverInfo; - osalMutexObjectInit(&msdp->mtx); } -void usbhmsdInit(void) { +static void _msd_init(void) { uint8_t i; for (i = 0; i < HAL_USBHMSD_MAX_INSTANCES; i++) { - usbhmsdObjectInit(&USBHMSD[i]); + _msd_object_init(&USBHMSD[i]); } for (i = 0; i < HAL_USBHMSD_MAX_LUNS; i++) { - usbhmsdLUNObjectInit(&MSBLKD[i]); + _lun_object_init(&MSBLKD[i]); } } #endif diff --git a/os/hal/src/usbh/hal_usbh_uvc.c b/os/hal/src/usbh/hal_usbh_uvc.c index b0507a0..a795cd8 100644 --- a/os/hal/src/usbh/hal_usbh_uvc.c +++ b/os/hal/src/usbh/hal_usbh_uvc.c @@ -27,9 +27,9 @@ #error "USBHUVC needs HAL_USBH_USE_IAD" #endif +#include <string.h> #include "usbh/dev/uvc.h" #include "usbh/internal.h" -#include <string.h> #if USBHUVC_DEBUG_ENABLE_TRACE #define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) @@ -66,17 +66,18 @@ USBHUVCDriver USBHUVCD[HAL_USBHUVC_MAX_INSTANCES]; - -static usbh_baseclassdriver_t *uvc_load(usbh_device_t *dev, +static void _uvc_init(void); +static usbh_baseclassdriver_t *_uvc_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem); -static void uvc_unload(usbh_baseclassdriver_t *drv); +static void _uvc_unload(usbh_baseclassdriver_t *drv); static const usbh_classdriver_vmt_t class_driver_vmt = { - uvc_load, - uvc_unload + _uvc_init, + _uvc_load, + _uvc_unload }; const usbh_classdriverinfo_t usbhuvcClassDriverInfo = { - 0x0e, 0x03, 0x00, "UVC", &class_driver_vmt + "UVC", &class_driver_vmt }; static bool _request(USBHUVCDriver *uvcdp, @@ -360,10 +361,8 @@ bool usbhuvcStreamStart(USBHUVCDriver *uvcdp, uint16_t min_ep_sz) { osalDbgCheck(msg); usbhURBObjectInit(&uvcdp->urb_iso, &uvcdp->ep_iso, _cb_iso, uvcdp, msg->data, uvcdp->ep_iso.wMaxPacketSize); } - osalSysLock(); - usbhURBSubmitI(&uvcdp->urb_iso); - osalOsRescheduleS(); - osalSysUnlock(); + + usbhURBSubmit(&uvcdp->urb_iso); ret = HAL_SUCCESS; goto exit; @@ -512,22 +511,13 @@ uint32_t usbhuvcEstimateRequiredEPSize(USBHUVCDriver *uvcdp, const uint8_t *form return (sz * mul) / div + 12; } -void usbhuvcObjectInit(USBHUVCDriver *uvcdp) { - osalDbgCheck(uvcdp != NULL); - memset(uvcdp, 0, sizeof(*uvcdp)); - uvcdp->info = &usbhuvcClassDriverInfo; - chMBObjectInit(&uvcdp->mb, uvcdp->mb_buff, HAL_USBHUVC_MAX_MAILBOX_SZ); - chMtxObjectInit(&uvcdp->mtx); - uvcdp->state = USBHUVC_STATE_STOP; -} - - -static usbh_baseclassdriver_t *uvc_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem) { +static usbh_baseclassdriver_t *_uvc_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem) { USBHUVCDriver *uvcdp; uint8_t i; - if (descriptor[1] != USBH_DT_INTERFACE_ASSOCIATION) + if (_usbh_match_descriptor(descriptor, rem, USBH_DT_INTERFACE_ASSOCIATION, + 0x0e, 0x03, 0x00) != HAL_SUCCESS) return NULL; /* alloc driver */ @@ -703,14 +693,14 @@ alloc_ok: osalSysLock(); usbhURBSubmitI(&uvcdp->urb_int); uvcdp->state = USBHUVC_STATE_ACTIVE; - osalOsRescheduleS(); + osalOsRescheduleS(); /* because of usbhURBSubmitI */ osalSysUnlock(); dev->keepFullCfgDesc++; return (usbh_baseclassdriver_t *)uvcdp; } -static void uvc_unload(usbh_baseclassdriver_t *drv) { +static void _uvc_unload(usbh_baseclassdriver_t *drv) { USBHUVCDriver *const uvcdp = (USBHUVCDriver *)drv; usbhuvcStreamStop(uvcdp); @@ -727,10 +717,19 @@ static void uvc_unload(usbh_baseclassdriver_t *drv) { osalSysUnlock(); } -void usbhuvcInit(void) { +static void _object_init(USBHUVCDriver *uvcdp) { + osalDbgCheck(uvcdp != NULL); + memset(uvcdp, 0, sizeof(*uvcdp)); + uvcdp->info = &usbhuvcClassDriverInfo; + chMBObjectInit(&uvcdp->mb, uvcdp->mb_buff, HAL_USBHUVC_MAX_MAILBOX_SZ); + chMtxObjectInit(&uvcdp->mtx); + uvcdp->state = USBHUVC_STATE_STOP; +} + +static void _uvc_init(void) { uint8_t i; for (i = 0; i < HAL_USBHUVC_MAX_INSTANCES; i++) { - usbhuvcObjectInit(&USBHUVCD[i]); + _object_init(&USBHUVCD[i]); } } |