Merge pull request #40 from fpoussin/usb-host-pull
USB-Host Driver Merged pull request #40 from fpoussin/usb-host-pull
This commit is contained in:
commit
31066ddfbf
|
@ -4,6 +4,13 @@ HALSRC += ${CHIBIOS_CONTRIB}/os/hal/src/hal_community.c \
|
||||||
${CHIBIOS_CONTRIB}/os/hal/src/nand.c \
|
${CHIBIOS_CONTRIB}/os/hal/src/nand.c \
|
||||||
${CHIBIOS_CONTRIB}/os/hal/src/onewire.c \
|
${CHIBIOS_CONTRIB}/os/hal/src/onewire.c \
|
||||||
${CHIBIOS_CONTRIB}/os/hal/src/eicu.c \
|
${CHIBIOS_CONTRIB}/os/hal/src/eicu.c \
|
||||||
${CHIBIOS_CONTRIB}/os/hal/src/crc.c
|
${CHIBIOS_CONTRIB}/os/hal/src/crc.c \
|
||||||
|
${CHIBIOS_CONTRIB}/os/hal/src/usbh.c \
|
||||||
|
${CHIBIOS_CONTRIB}/os/hal/src/usbh/usbh_debug.c \
|
||||||
|
${CHIBIOS_CONTRIB}/os/hal/src/usbh/usbh_desciter.c \
|
||||||
|
${CHIBIOS_CONTRIB}/os/hal/src/usbh/usbh_hub.c \
|
||||||
|
${CHIBIOS_CONTRIB}/os/hal/src/usbh/usbh_msd.c \
|
||||||
|
${CHIBIOS_CONTRIB}/os/hal/src/usbh/usbh_ftdi.c \
|
||||||
|
${CHIBIOS_CONTRIB}/os/hal/src/usbh/usbh_uvc.c
|
||||||
|
|
||||||
HALINC += ${CHIBIOS_CONTRIB}/os/hal/include
|
HALINC += ${CHIBIOS_CONTRIB}/os/hal/include
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
/* Normal drivers.*/
|
/* Normal drivers.*/
|
||||||
#include "nand.h"
|
#include "nand.h"
|
||||||
#include "eicu.h"
|
#include "eicu.h"
|
||||||
|
#include "usbh.h"
|
||||||
|
|
||||||
/* Complex drivers.*/
|
/* Complex drivers.*/
|
||||||
#include "onewire.h"
|
#include "onewire.h"
|
||||||
|
|
|
@ -0,0 +1,439 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||||
|
Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef USBH_H_
|
||||||
|
#define USBH_H_
|
||||||
|
|
||||||
|
#include "hal.h"
|
||||||
|
|
||||||
|
#ifndef HAL_USE_USBH
|
||||||
|
#define HAL_USE_USBH FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAL_USBH_USE_FTDI
|
||||||
|
#define HAL_USBH_USE_FTDI FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAL_USBH_USE_HUB
|
||||||
|
#define HAL_USBH_USE_HUB FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAL_USBH_USE_MSD
|
||||||
|
#define HAL_USBH_USE_MSD FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAL_USBH_USE_UVC
|
||||||
|
#define HAL_USBH_USE_UVC FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAL_USE_USBH
|
||||||
|
|
||||||
|
#include "osal.h"
|
||||||
|
#include "usbh/list.h"
|
||||||
|
#include "usbh/defs.h"
|
||||||
|
|
||||||
|
/* TODO:
|
||||||
|
*
|
||||||
|
* - Integrate VBUS power switching functionality to the API.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Derived constants and error checks. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
#if !HAL_USBH_USE_HUB
|
||||||
|
#define USBH_MAX_ADDRESSES 1
|
||||||
|
#else
|
||||||
|
#define USBH_MAX_ADDRESSES (HAL_USBHHUB_MAX_PORTS + 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum usbh_status {
|
||||||
|
USBH_STATUS_STOPPED = 0,
|
||||||
|
USBH_STATUS_STARTED,
|
||||||
|
USBH_STATUS_SUSPENDED,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum usbh_devstatus {
|
||||||
|
USBH_DEVSTATUS_DISCONNECTED = 0,
|
||||||
|
USBH_DEVSTATUS_ATTACHED,
|
||||||
|
USBH_DEVSTATUS_CONNECTED,
|
||||||
|
USBH_DEVSTATUS_DEFAULT,
|
||||||
|
USBH_DEVSTATUS_ADDRESS,
|
||||||
|
USBH_DEVSTATUS_CONFIGURED,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum usbh_devspeed {
|
||||||
|
USBH_DEVSPEED_LOW = 0,
|
||||||
|
USBH_DEVSPEED_FULL,
|
||||||
|
USBH_DEVSPEED_HIGH,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum usbh_epdir {
|
||||||
|
USBH_EPDIR_IN = 0x80,
|
||||||
|
USBH_EPDIR_OUT = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
enum usbh_eptype {
|
||||||
|
USBH_EPTYPE_CTRL = 0,
|
||||||
|
USBH_EPTYPE_ISO = 1,
|
||||||
|
USBH_EPTYPE_BULK = 2,
|
||||||
|
USBH_EPTYPE_INT = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum usbh_epstatus {
|
||||||
|
USBH_EPSTATUS_UNINITIALIZED = 0,
|
||||||
|
USBH_EPSTATUS_CLOSED,
|
||||||
|
USBH_EPSTATUS_OPEN,
|
||||||
|
USBH_EPSTATUS_HALTED,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum usbh_urbstatus {
|
||||||
|
USBH_URBSTATUS_UNINITIALIZED = 0,
|
||||||
|
USBH_URBSTATUS_INITIALIZED,
|
||||||
|
USBH_URBSTATUS_PENDING,
|
||||||
|
// USBH_URBSTATUS_QUEUED,
|
||||||
|
USBH_URBSTATUS_ERROR,
|
||||||
|
USBH_URBSTATUS_TIMEOUT,
|
||||||
|
USBH_URBSTATUS_CANCELLED,
|
||||||
|
USBH_URBSTATUS_STALL,
|
||||||
|
USBH_URBSTATUS_DISCONNECTED,
|
||||||
|
// USBH_URBSTATUS_EPCLOSED,
|
||||||
|
USBH_URBSTATUS_OK,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver data structures and types. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/* forward declarations */
|
||||||
|
typedef struct USBHDriver USBHDriver;
|
||||||
|
typedef struct usbh_port usbh_port_t;
|
||||||
|
typedef struct usbh_device usbh_device_t;
|
||||||
|
typedef struct usbh_ep usbh_ep_t;
|
||||||
|
typedef struct usbh_urb usbh_urb_t;
|
||||||
|
typedef struct usbh_baseclassdriver usbh_baseclassdriver_t;
|
||||||
|
typedef struct usbh_classdriverinfo usbh_classdriverinfo_t;
|
||||||
|
#if HAL_USBH_USE_HUB
|
||||||
|
typedef struct USBHHubDriver USBHHubDriver;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* typedefs */
|
||||||
|
typedef enum usbh_status usbh_status_t;
|
||||||
|
typedef enum usbh_devspeed usbh_devspeed_t;
|
||||||
|
typedef enum usbh_devstatus usbh_devstatus_t;
|
||||||
|
typedef enum usbh_epdir usbh_epdir_t;
|
||||||
|
typedef enum usbh_eptype usbh_eptype_t;
|
||||||
|
typedef enum usbh_epstatus usbh_epstatus_t;
|
||||||
|
typedef enum usbh_urbstatus usbh_urbstatus_t;
|
||||||
|
typedef uint16_t usbh_portstatus_t;
|
||||||
|
typedef uint16_t usbh_portcstatus_t;
|
||||||
|
typedef void (*usbh_completion_cb)(usbh_urb_t *);
|
||||||
|
|
||||||
|
/* include the low level driver; the required definitions are above */
|
||||||
|
#include "usbh_lld.h"
|
||||||
|
|
||||||
|
#define USBH_DEFINE_BUFFER(type, name) USBH_LLD_DEFINE_BUFFER(type, name)
|
||||||
|
|
||||||
|
struct usbh_urb {
|
||||||
|
usbh_ep_t *ep;
|
||||||
|
|
||||||
|
void *userData;
|
||||||
|
usbh_completion_cb callback;
|
||||||
|
|
||||||
|
const void *setup_buff;
|
||||||
|
void *buff;
|
||||||
|
uint32_t requestedLength;
|
||||||
|
uint32_t actualLength;
|
||||||
|
|
||||||
|
usbh_urbstatus_t status;
|
||||||
|
|
||||||
|
thread_reference_t waitingThread;
|
||||||
|
thread_reference_t abortingThread;
|
||||||
|
|
||||||
|
/* Low level part */
|
||||||
|
_usbh_urb_ll_data
|
||||||
|
};
|
||||||
|
|
||||||
|
struct usbh_ep {
|
||||||
|
usbh_device_t *device;
|
||||||
|
usbh_ep_t *next;
|
||||||
|
|
||||||
|
usbh_epstatus_t status;
|
||||||
|
uint8_t address;
|
||||||
|
bool in;
|
||||||
|
usbh_eptype_t type;
|
||||||
|
uint16_t wMaxPacketSize;
|
||||||
|
uint8_t bInterval;
|
||||||
|
|
||||||
|
/* debug */
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
/* Low-level part */
|
||||||
|
_usbh_ep_ll_data
|
||||||
|
};
|
||||||
|
|
||||||
|
struct usbh_device {
|
||||||
|
USBHDriver *host; /* shortcut to host */
|
||||||
|
|
||||||
|
usbh_ep_t ctrl;
|
||||||
|
usbh_ep_t *endpoints;
|
||||||
|
|
||||||
|
usbh_baseclassdriver_t *drivers;
|
||||||
|
|
||||||
|
uint16_t langID0;
|
||||||
|
|
||||||
|
usbh_devstatus_t status;
|
||||||
|
usbh_devspeed_t speed;
|
||||||
|
|
||||||
|
USBH_DEFINE_BUFFER(usbh_device_descriptor_t, devDesc);
|
||||||
|
unsigned char align_bytes[2];
|
||||||
|
USBH_DEFINE_BUFFER(usbh_config_descriptor_t, basicConfigDesc);
|
||||||
|
|
||||||
|
uint8_t *fullConfigurationDescriptor;
|
||||||
|
uint8_t keepFullCfgDesc;
|
||||||
|
|
||||||
|
uint8_t address;
|
||||||
|
uint8_t bConfiguration;
|
||||||
|
|
||||||
|
/* Low level part */
|
||||||
|
_usbh_device_ll_data
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct usbh_port {
|
||||||
|
#if HAL_USBH_USE_HUB
|
||||||
|
USBHHubDriver *hub;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
usbh_portstatus_t status;
|
||||||
|
usbh_portcstatus_t c_status;
|
||||||
|
|
||||||
|
usbh_port_t *next;
|
||||||
|
|
||||||
|
uint8_t number;
|
||||||
|
|
||||||
|
usbh_device_t device;
|
||||||
|
|
||||||
|
/* Low level part */
|
||||||
|
_usbh_port_ll_data
|
||||||
|
};
|
||||||
|
|
||||||
|
struct USBHDriver {
|
||||||
|
usbh_status_t status;
|
||||||
|
uint8_t address_bitmap[(USBH_MAX_ADDRESSES + 7) / 8];
|
||||||
|
|
||||||
|
usbh_port_t rootport;
|
||||||
|
|
||||||
|
#if HAL_USBH_USE_HUB
|
||||||
|
struct list_head hubs;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Low level part */
|
||||||
|
_usbhdriver_ll_data
|
||||||
|
|
||||||
|
#if USBH_DEBUG_ENABLE
|
||||||
|
/* debug */
|
||||||
|
uint8_t dbg_buff[USBH_DEBUG_BUFFER];
|
||||||
|
THD_WORKING_AREA(waDebug, 512);
|
||||||
|
input_queue_t iq;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* External declarations. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
#if STM32_USBH_USE_OTG1
|
||||||
|
extern USBHDriver USBHD1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if STM32_USBH_USE_OTG2
|
||||||
|
extern USBHDriver USBHD2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Main driver API. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Main functions */
|
||||||
|
void usbhObjectInit(USBHDriver *usbh);
|
||||||
|
void usbhInit(void);
|
||||||
|
void usbhStart(USBHDriver *usbh);
|
||||||
|
void usbhStop(USBHDriver *usbh);
|
||||||
|
void usbhSuspend(USBHDriver *usbh);
|
||||||
|
void usbhResume(USBHDriver *usbh);
|
||||||
|
|
||||||
|
/* Device-related */
|
||||||
|
#if USBH_DEBUG_ENABLE && USBH_DEBUG_ENABLE_INFO
|
||||||
|
void usbhDevicePrintInfo(usbh_device_t *dev);
|
||||||
|
void usbhDevicePrintConfiguration(const uint8_t *descriptor, uint16_t rem);
|
||||||
|
#else
|
||||||
|
# define usbhDevicePrintInfo(dev) do {} while(0)
|
||||||
|
# define usbhDevicePrintConfiguration(descriptor, rem) do {} while(0)
|
||||||
|
#endif
|
||||||
|
bool usbhDeviceReadString(usbh_device_t *dev, char *dest, uint8_t size,
|
||||||
|
uint8_t index, uint16_t langID);
|
||||||
|
static inline usbh_port_t *usbhDeviceGetPort(usbh_device_t *dev) {
|
||||||
|
return container_of(dev, usbh_port_t, device);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Synchronous API */
|
||||||
|
usbh_urbstatus_t usbhBulkTransfer(usbh_ep_t *ep,
|
||||||
|
void *data,
|
||||||
|
uint32_t len,
|
||||||
|
uint32_t *actual_len,
|
||||||
|
systime_t timeout);
|
||||||
|
usbh_urbstatus_t usbhControlRequest(usbh_device_t *dev,
|
||||||
|
uint8_t bmRequestType,
|
||||||
|
uint8_t bRequest,
|
||||||
|
uint16_t wValue,
|
||||||
|
uint16_t wIndex,
|
||||||
|
uint16_t wLength,
|
||||||
|
uint8_t *buff);
|
||||||
|
usbh_urbstatus_t usbhControlRequestExtended(usbh_device_t *dev,
|
||||||
|
const usbh_control_request_t *req,
|
||||||
|
uint8_t *buff,
|
||||||
|
uint32_t *actual_len,
|
||||||
|
systime_t timeout);
|
||||||
|
|
||||||
|
/* Standard request helpers */
|
||||||
|
bool usbhStdReqGetDeviceDescriptor(usbh_device_t *dev,
|
||||||
|
uint16_t wLength,
|
||||||
|
uint8_t *buf);
|
||||||
|
bool usbhStdReqGetConfigurationDescriptor(usbh_device_t *dev,
|
||||||
|
uint8_t index,
|
||||||
|
uint16_t wLength,
|
||||||
|
uint8_t *buf);
|
||||||
|
bool usbhStdReqGetStringDescriptor(usbh_device_t *dev,
|
||||||
|
uint8_t index,
|
||||||
|
uint16_t langID,
|
||||||
|
uint16_t wLength,
|
||||||
|
uint8_t *buf);
|
||||||
|
bool usbhStdReqSetInterface(usbh_device_t *dev,
|
||||||
|
uint8_t bInterfaceNumber,
|
||||||
|
uint8_t bAlternateSetting);
|
||||||
|
bool usbhStdReqGetInterface(usbh_device_t *dev,
|
||||||
|
uint8_t bInterfaceNumber,
|
||||||
|
uint8_t *bAlternateSetting);
|
||||||
|
|
||||||
|
/* Endpoint/pipe management */
|
||||||
|
void usbhEPObjectInit(usbh_ep_t *ep, usbh_device_t *dev, const usbh_endpoint_descriptor_t *desc);
|
||||||
|
static inline void usbhEPOpen(usbh_ep_t *ep) {
|
||||||
|
osalDbgCheck(ep != 0);
|
||||||
|
osalSysLock();
|
||||||
|
osalDbgAssert(ep->status == USBH_EPSTATUS_CLOSED, "invalid state");
|
||||||
|
usbh_lld_ep_open(ep);
|
||||||
|
ep->next = ep->device->endpoints;
|
||||||
|
ep->device->endpoints = ep;
|
||||||
|
osalSysUnlock();
|
||||||
|
}
|
||||||
|
static inline void usbhEPCloseS(usbh_ep_t *ep) {
|
||||||
|
osalDbgCheck(ep != 0);
|
||||||
|
osalDbgCheckClassS();
|
||||||
|
osalDbgAssert(ep->status != USBH_EPSTATUS_UNINITIALIZED, "invalid state");
|
||||||
|
if (ep->status == USBH_EPSTATUS_CLOSED) {
|
||||||
|
osalOsRescheduleS();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
usbh_lld_ep_close(ep);
|
||||||
|
}
|
||||||
|
static inline void usbhEPClose(usbh_ep_t *ep) {
|
||||||
|
osalSysLock();
|
||||||
|
usbhEPCloseS(ep);
|
||||||
|
osalSysUnlock();
|
||||||
|
}
|
||||||
|
static inline void usbhEPResetI(usbh_ep_t *ep) {
|
||||||
|
osalDbgCheckClassI();
|
||||||
|
osalDbgCheck(ep != NULL);
|
||||||
|
usbh_lld_epreset(ep);
|
||||||
|
}
|
||||||
|
static inline bool usbhEPIsPeriodic(usbh_ep_t *ep) {
|
||||||
|
osalDbgCheck(ep != NULL);
|
||||||
|
return (ep->type & 1) != 0;
|
||||||
|
}
|
||||||
|
static inline bool usbhURBIsBusy(usbh_urb_t *urb) {
|
||||||
|
osalDbgCheck(urb != NULL);
|
||||||
|
return (urb->status == USBH_URBSTATUS_PENDING);
|
||||||
|
}
|
||||||
|
static inline void usbhEPSetName(usbh_ep_t *ep, const char *name) {
|
||||||
|
ep->name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* URB management */
|
||||||
|
void usbhURBObjectInit(usbh_urb_t *urb, usbh_ep_t *ep, usbh_completion_cb callback,
|
||||||
|
void *user, void *buff, uint32_t len);
|
||||||
|
void usbhURBObjectResetI(usbh_urb_t *urb);
|
||||||
|
void usbhURBSubmitI(usbh_urb_t *urb);
|
||||||
|
bool usbhURBCancelI(usbh_urb_t *urb);
|
||||||
|
msg_t usbhURBSubmitAndWaitS(usbh_urb_t *urb, systime_t timeout);
|
||||||
|
void usbhURBCancelAndWaitS(usbh_urb_t *urb);
|
||||||
|
msg_t usbhURBWaitTimeoutS(usbh_urb_t *urb, systime_t timeout);
|
||||||
|
|
||||||
|
/* Main loop */
|
||||||
|
void usbhMainLoop(USBHDriver *usbh);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Class driver definitions and API. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
typedef struct usbh_classdriver_vmt usbh_classdriver_vmt_t;
|
||||||
|
struct usbh_classdriver_vmt {
|
||||||
|
usbh_baseclassdriver_t *(*load)(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem);
|
||||||
|
void (*unload)(usbh_baseclassdriver_t *drv);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct usbh_classdriverinfo {
|
||||||
|
int16_t class;
|
||||||
|
int16_t subclass;
|
||||||
|
int16_t protocol;
|
||||||
|
const char *name;
|
||||||
|
const usbh_classdriver_vmt_t *vmt;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define _usbh_base_classdriver_data \
|
||||||
|
const usbh_classdriverinfo_t *info; \
|
||||||
|
usbh_device_t *dev; \
|
||||||
|
usbh_baseclassdriver_t *next;
|
||||||
|
|
||||||
|
struct usbh_baseclassdriver {
|
||||||
|
_usbh_base_classdriver_data
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Helper functions. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
#include <usbh/desciter.h> /* descriptor iterators */
|
||||||
|
#include <usbh/debug.h> /* debug */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* USBH_H_ */
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||||
|
Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef USBH_DEBUG_H_
|
||||||
|
#define USBH_DEBUG_H_
|
||||||
|
|
||||||
|
#include "usbh.h"
|
||||||
|
|
||||||
|
#if HAL_USE_USBH
|
||||||
|
|
||||||
|
//TODO: Debug is only for USBHD1, make it generic.
|
||||||
|
|
||||||
|
#if USBH_DEBUG_ENABLE
|
||||||
|
void usbDbgPrintf(const char *fmt, ...);
|
||||||
|
void usbDbgPuts(const char *s);
|
||||||
|
void usbDbgInit(USBHDriver *host);
|
||||||
|
void usbDbgReset(void);
|
||||||
|
void usbDbgSystemHalted(void);
|
||||||
|
#else
|
||||||
|
#define usbDbgPrintf(fmt, ...) do {} while(0)
|
||||||
|
#define usbDbgPuts(s) do {} while(0)
|
||||||
|
#define usbDbgInit(host) do {} while(0)
|
||||||
|
#define usbDbgReset() do {} while(0)
|
||||||
|
#define usbDbgSystemHalted() do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* USBH_DEBUG_H_ */
|
|
@ -0,0 +1,160 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||||
|
Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef USBH_DEFS_H_
|
||||||
|
#define USBH_DEFS_H_
|
||||||
|
|
||||||
|
#include "hal.h"
|
||||||
|
|
||||||
|
#if HAL_USE_USBH
|
||||||
|
|
||||||
|
#include "osal.h"
|
||||||
|
|
||||||
|
#ifdef __IAR_SYSTEMS_ICC__
|
||||||
|
#define PACKED_STRUCT typedef PACKED_VAR struct
|
||||||
|
#else
|
||||||
|
#define PACKED_STRUCT typedef struct PACKED_VAR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PACKED_STRUCT {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
uint16_t bcdUSB;
|
||||||
|
uint8_t bDeviceClass;
|
||||||
|
uint8_t bDeviceSubClass;
|
||||||
|
uint8_t bDeviceProtocol;
|
||||||
|
uint8_t bMaxPacketSize0;
|
||||||
|
uint16_t idVendor;
|
||||||
|
uint16_t idProduct;
|
||||||
|
uint16_t bcdDevice;
|
||||||
|
uint8_t iManufacturer;
|
||||||
|
uint8_t iProduct;
|
||||||
|
uint8_t iSerialNumber;
|
||||||
|
uint8_t bNumConfigurations;
|
||||||
|
} usbh_device_descriptor_t;
|
||||||
|
#define USBH_DT_DEVICE 0x01
|
||||||
|
#define USBH_DT_DEVICE_SIZE 18
|
||||||
|
|
||||||
|
PACKED_STRUCT {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
uint16_t wTotalLength;
|
||||||
|
uint8_t bNumInterfaces;
|
||||||
|
uint8_t bConfigurationValue;
|
||||||
|
uint8_t iConfiguration;
|
||||||
|
uint8_t bmAttributes;
|
||||||
|
uint8_t bMaxPower;
|
||||||
|
} usbh_config_descriptor_t;
|
||||||
|
#define USBH_DT_CONFIG 0x02
|
||||||
|
#define USBH_DT_CONFIG_SIZE 9
|
||||||
|
|
||||||
|
PACKED_STRUCT {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
uint16_t wData[1];
|
||||||
|
} usbh_string_descriptor_t;
|
||||||
|
#define USBH_DT_STRING 0x03
|
||||||
|
#define USBH_DT_STRING_SIZE 2
|
||||||
|
|
||||||
|
PACKED_STRUCT {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
uint8_t bInterfaceNumber;
|
||||||
|
uint8_t bAlternateSetting;
|
||||||
|
uint8_t bNumEndpoints;
|
||||||
|
uint8_t bInterfaceClass;
|
||||||
|
uint8_t bInterfaceSubClass;
|
||||||
|
uint8_t bInterfaceProtocol;
|
||||||
|
uint8_t iInterface;
|
||||||
|
} usbh_interface_descriptor_t;
|
||||||
|
#define USBH_DT_INTERFACE 0x04
|
||||||
|
#define USBH_DT_INTERFACE_SIZE 9
|
||||||
|
|
||||||
|
PACKED_STRUCT {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
uint8_t bEndpointAddress;
|
||||||
|
uint8_t bmAttributes;
|
||||||
|
uint16_t wMaxPacketSize;
|
||||||
|
uint8_t bInterval;
|
||||||
|
} usbh_endpoint_descriptor_t;
|
||||||
|
#define USBH_DT_ENDPOINT 0x05
|
||||||
|
#define USBH_DT_ENDPOINT_SIZE 7
|
||||||
|
|
||||||
|
PACKED_STRUCT {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
uint8_t bFirstInterface;
|
||||||
|
uint8_t bInterfaceCount;
|
||||||
|
uint8_t bFunctionClass;
|
||||||
|
uint8_t bFunctionSubClass;
|
||||||
|
uint8_t bFunctionProtocol;
|
||||||
|
uint8_t iFunction;
|
||||||
|
} usbh_ia_descriptor_t;
|
||||||
|
#define USBH_DT_INTERFACE_ASSOCIATION 0x0b
|
||||||
|
#define USBH_DT_INTERFACE_ASSOCIATION_SIZE 8
|
||||||
|
|
||||||
|
PACKED_STRUCT {
|
||||||
|
uint8_t bDescLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
uint8_t bNbrPorts;
|
||||||
|
uint16_t wHubCharacteristics;
|
||||||
|
uint8_t bPwrOn2PwrGood;
|
||||||
|
uint8_t bHubContrCurrent;
|
||||||
|
uint32_t DeviceRemovable;
|
||||||
|
} usbh_hub_descriptor_t;
|
||||||
|
#define USBH_DT_HUB 0x29
|
||||||
|
#define USBH_DT_HUB_SIZE (7 + 4)
|
||||||
|
|
||||||
|
PACKED_STRUCT {
|
||||||
|
uint8_t bmRequestType;
|
||||||
|
uint8_t bRequest;
|
||||||
|
uint16_t wValue;
|
||||||
|
uint16_t wIndex;
|
||||||
|
uint16_t wLength;
|
||||||
|
} usbh_control_request_t;
|
||||||
|
|
||||||
|
|
||||||
|
#define USBH_REQ_GET_STATUS 0x00
|
||||||
|
#define USBH_REQ_CLEAR_FEATURE 0x01
|
||||||
|
#define USBH_REQ_SET_FEATURE 0x03
|
||||||
|
#define USBH_REQ_SET_ADDRESS 0x05
|
||||||
|
#define USBH_REQ_GET_DESCRIPTOR 0x06
|
||||||
|
#define USBH_REQ_SET_DESCRIPTOR 0x07
|
||||||
|
#define USBH_REQ_GET_CONFIGURATION 0x08
|
||||||
|
#define USBH_REQ_SET_CONFIGURATION 0x09
|
||||||
|
#define USBH_REQ_GET_INTERFACE 0x0A
|
||||||
|
#define USBH_REQ_SET_INTERFACE 0x0B
|
||||||
|
#define USBH_REQ_SYNCH_FRAME 0x0C
|
||||||
|
|
||||||
|
|
||||||
|
#define USBH_REQTYPE_IN 0x80
|
||||||
|
#define USBH_REQTYPE_OUT 0x00
|
||||||
|
|
||||||
|
#define USBH_REQTYPE_STANDARD 0x00
|
||||||
|
#define USBH_REQTYPE_CLASS 0x20
|
||||||
|
#define USBH_REQTYPE_VENDOR 0x40
|
||||||
|
|
||||||
|
#define USBH_REQTYPE_DEVICE 0x00
|
||||||
|
#define USBH_REQTYPE_INTERFACE 0x01
|
||||||
|
#define USBH_REQTYPE_ENDPOINT 0x02
|
||||||
|
#define USBH_REQTYPE_OTHER 0x03
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* USBH_DEFS_H_ */
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||||
|
Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef USBH_DESCITER_H_
|
||||||
|
#define USBH_DESCITER_H_
|
||||||
|
|
||||||
|
#include "hal.h"
|
||||||
|
|
||||||
|
#if HAL_USE_USBH
|
||||||
|
|
||||||
|
#include "usbh/defs.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* DESCRIPTOR PARSING */
|
||||||
|
#define _generic_iterator_fields \
|
||||||
|
const uint8_t *curr; \
|
||||||
|
uint16_t rem; \
|
||||||
|
bool valid;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
_generic_iterator_fields
|
||||||
|
} generic_iterator_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
_generic_iterator_fields
|
||||||
|
const usbh_ia_descriptor_t *iad;
|
||||||
|
} if_iterator_t;
|
||||||
|
|
||||||
|
void cfg_iter_init(generic_iterator_t *icfg, const uint8_t *buff, uint16_t rem);
|
||||||
|
void if_iter_init(if_iterator_t *iif, const generic_iterator_t *icfg);
|
||||||
|
void ep_iter_init(generic_iterator_t *iep, const if_iterator_t *iif);
|
||||||
|
void cs_iter_init(generic_iterator_t *ics, const generic_iterator_t *iter);
|
||||||
|
void if_iter_next(if_iterator_t *iif);
|
||||||
|
void ep_iter_next(generic_iterator_t *iep);
|
||||||
|
void cs_iter_next(generic_iterator_t *ics);
|
||||||
|
static inline const usbh_config_descriptor_t *cfg_get(generic_iterator_t *icfg) {
|
||||||
|
return (const usbh_config_descriptor_t *)icfg->curr;
|
||||||
|
}
|
||||||
|
static inline const usbh_interface_descriptor_t *if_get(if_iterator_t *iif) {
|
||||||
|
return (const usbh_interface_descriptor_t *)iif->curr;
|
||||||
|
}
|
||||||
|
static inline const usbh_endpoint_descriptor_t *ep_get(generic_iterator_t *iep) {
|
||||||
|
return (const usbh_endpoint_descriptor_t *)iep->curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* USBH_DESCITER_H_ */
|
|
@ -0,0 +1,154 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||||
|
Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef USBH_FTDI_H_
|
||||||
|
#define USBH_FTDI_H_
|
||||||
|
|
||||||
|
#include "usbh.h"
|
||||||
|
|
||||||
|
#if HAL_USE_USBH && HAL_USBH_USE_FTDI
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver pre-compile time settings. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Derived constants and error checks. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
#define USBHFTDI_FRAMING_DATABITS_7 (0x7 << 0)
|
||||||
|
#define USBHFTDI_FRAMING_DATABITS_8 (0x8 << 0)
|
||||||
|
#define USBHFTDI_FRAMING_PARITY_NONE (0x0 << 8)
|
||||||
|
#define USBHFTDI_FRAMING_PARITY_NONE (0x0 << 8)
|
||||||
|
#define USBHFTDI_FRAMING_PARITY_ODD (0x1 << 8)
|
||||||
|
#define USBHFTDI_FRAMING_PARITY_EVEN (0x2 << 8)
|
||||||
|
#define USBHFTDI_FRAMING_PARITY_MARK (0x3 << 8)
|
||||||
|
#define USBHFTDI_FRAMING_PARITY_SPACE (0x4 << 8)
|
||||||
|
#define USBHFTDI_FRAMING_STOP_BITS_1 (0x0 << 11)
|
||||||
|
#define USBHFTDI_FRAMING_STOP_BITS_15 (0x1 << 11)
|
||||||
|
#define USBHFTDI_FRAMING_STOP_BITS_2 (0x2 << 11)
|
||||||
|
|
||||||
|
#define USBHFTDI_HANDSHAKE_NONE (0x0)
|
||||||
|
#define USBHFTDI_HANDSHAKE_RTS_CTS (0x1)
|
||||||
|
#define USBHFTDI_HANDSHAKE_DTR_DSR (0x2)
|
||||||
|
#define USBHFTDI_HANDSHAKE_XON_XOFF (0x4)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver data structures and types. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
typedef struct {
|
||||||
|
uint32_t speed;
|
||||||
|
uint16_t framing;
|
||||||
|
uint8_t handshake;
|
||||||
|
uint8_t xon_character;
|
||||||
|
uint8_t xoff_character;
|
||||||
|
} USBHFTDIPortConfig;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
USBHFTDI_TYPE_A,
|
||||||
|
USBHFTDI_TYPE_B,
|
||||||
|
USBHFTDI_TYPE_H,
|
||||||
|
} usbhftdi_type_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
USBHFTDIP_STATE_UNINIT = 0,
|
||||||
|
USBHFTDIP_STATE_STOP = 1,
|
||||||
|
USBHFTDIP_STATE_ACTIVE = 2,
|
||||||
|
USBHFTDIP_STATE_READY = 3
|
||||||
|
} usbhftdip_state_t;
|
||||||
|
|
||||||
|
|
||||||
|
#define _ftdi_port_driver_methods \
|
||||||
|
_base_asynchronous_channel_methods
|
||||||
|
|
||||||
|
struct FTDIPortDriverVMT {
|
||||||
|
_ftdi_port_driver_methods
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct USBHFTDIPortDriver USBHFTDIPortDriver;
|
||||||
|
typedef struct USBHFTDIDriver USBHFTDIDriver;
|
||||||
|
|
||||||
|
struct USBHFTDIPortDriver {
|
||||||
|
/* inherited from abstract asyncrhonous channel driver */
|
||||||
|
const struct FTDIPortDriverVMT *vmt;
|
||||||
|
_base_asynchronous_channel_data
|
||||||
|
|
||||||
|
USBHFTDIDriver *ftdip;
|
||||||
|
|
||||||
|
usbhftdip_state_t state;
|
||||||
|
|
||||||
|
usbh_ep_t epin;
|
||||||
|
usbh_urb_t iq_urb;
|
||||||
|
threads_queue_t iq_waiting;
|
||||||
|
uint32_t iq_counter;
|
||||||
|
USBH_DEFINE_BUFFER(uint8_t, iq_buff[64]);
|
||||||
|
uint8_t *iq_ptr;
|
||||||
|
|
||||||
|
|
||||||
|
usbh_ep_t epout;
|
||||||
|
usbh_urb_t oq_urb;
|
||||||
|
threads_queue_t oq_waiting;
|
||||||
|
uint32_t oq_counter;
|
||||||
|
USBH_DEFINE_BUFFER(uint8_t, oq_buff[64]);
|
||||||
|
uint8_t *oq_ptr;
|
||||||
|
|
||||||
|
virtual_timer_t vt;
|
||||||
|
uint8_t ifnum;
|
||||||
|
|
||||||
|
USBHFTDIPortDriver *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct USBHFTDIDriver {
|
||||||
|
/* inherited from abstract class driver */
|
||||||
|
_usbh_base_classdriver_data
|
||||||
|
|
||||||
|
usbhftdi_type_t type;
|
||||||
|
USBHFTDIPortDriver *ports;
|
||||||
|
|
||||||
|
mutex_t mtx;
|
||||||
|
} USBHFTDIDriver;
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver macros. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* External declarations. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
extern USBHFTDIDriver USBHFTDID[HAL_USBHFTDI_MAX_INSTANCES];
|
||||||
|
extern USBHFTDIPortDriver FTDIPD[HAL_USBHFTDI_MAX_PORTS];
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/* FTDI device driver */
|
||||||
|
void usbhftdiObjectInit(USBHFTDIDriver *ftdip);
|
||||||
|
|
||||||
|
/* FTDI port driver */
|
||||||
|
void usbhftdipObjectInit(USBHFTDIPortDriver *ftdipp);
|
||||||
|
void usbhftdipStart(USBHFTDIPortDriver *ftdipp, const USBHFTDIPortConfig *config);
|
||||||
|
void usbhftdipStop(USBHFTDIPortDriver *ftdipp);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* USBH_FTDI_H_ */
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||||
|
Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef USBH_HUB_H_
|
||||||
|
#define USBH_HUB_H_
|
||||||
|
|
||||||
|
#include "usbh.h"
|
||||||
|
|
||||||
|
#if HAL_USE_USBH
|
||||||
|
#if HAL_USBH_USE_HUB
|
||||||
|
|
||||||
|
typedef struct USBHHubDriver {
|
||||||
|
/* inherited from abstract class driver */
|
||||||
|
_usbh_base_classdriver_data
|
||||||
|
|
||||||
|
struct list_head node;
|
||||||
|
|
||||||
|
usbh_ep_t epint;
|
||||||
|
usbh_urb_t urb;
|
||||||
|
|
||||||
|
USBH_DEFINE_BUFFER(uint8_t, scbuff[4]);
|
||||||
|
volatile uint32_t statuschange;
|
||||||
|
uint16_t status;
|
||||||
|
uint16_t c_status;
|
||||||
|
|
||||||
|
usbh_port_t *ports;
|
||||||
|
|
||||||
|
USBH_DEFINE_BUFFER(usbh_hub_descriptor_t, hubDesc);
|
||||||
|
|
||||||
|
/* Low level part */
|
||||||
|
_usbh_hub_ll_data
|
||||||
|
|
||||||
|
} USBHHubDriver;
|
||||||
|
|
||||||
|
extern USBHHubDriver USBHHUBD[HAL_USBHHUB_MAX_INSTANCES];
|
||||||
|
|
||||||
|
|
||||||
|
usbh_urbstatus_t usbhhubControlRequest(USBHDriver *host, USBHHubDriver *hub,
|
||||||
|
uint8_t bmRequestType,
|
||||||
|
uint8_t bRequest,
|
||||||
|
uint16_t wValue,
|
||||||
|
uint16_t wIndex,
|
||||||
|
uint16_t wLength,
|
||||||
|
uint8_t *buf);
|
||||||
|
|
||||||
|
|
||||||
|
static inline usbh_urbstatus_t usbhhubClearFeaturePort(usbh_port_t *port, uint8_t feature) {
|
||||||
|
return usbhhubControlRequest(port->device.host, port->hub,
|
||||||
|
USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_OTHER,
|
||||||
|
USBH_REQ_CLEAR_FEATURE,
|
||||||
|
feature,
|
||||||
|
port->number,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline usbh_urbstatus_t usbhhubClearFeatureHub(USBHDriver *host, USBHHubDriver *hub, uint8_t feature) {
|
||||||
|
return usbhhubControlRequest(host, hub,
|
||||||
|
USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_DEVICE,
|
||||||
|
USBH_REQ_CLEAR_FEATURE,
|
||||||
|
feature,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline usbh_urbstatus_t usbhhubSetFeaturePort(usbh_port_t *port, uint8_t feature) {
|
||||||
|
return usbhhubControlRequest(port->device.host, port->hub,
|
||||||
|
USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_OTHER,
|
||||||
|
USBH_REQ_SET_FEATURE,
|
||||||
|
feature,
|
||||||
|
port->number,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usbhhubObjectInit(USBHHubDriver *hubdp);
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline usbh_urbstatus_t usbhhubControlRequest(USBHDriver *host,
|
||||||
|
uint8_t bmRequestType,
|
||||||
|
uint8_t bRequest,
|
||||||
|
uint16_t wValue,
|
||||||
|
uint16_t wIndex,
|
||||||
|
uint16_t wLength,
|
||||||
|
uint8_t *buf) {
|
||||||
|
return usbh_lld_root_hub_request(host, bmRequestType, bRequest, wValue, wIndex, wLength, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline usbh_urbstatus_t usbhhubClearFeaturePort(usbh_port_t *port, uint8_t feature) {
|
||||||
|
return usbhhubControlRequest(port->device.host,
|
||||||
|
USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_OTHER,
|
||||||
|
USBH_REQ_CLEAR_FEATURE,
|
||||||
|
feature,
|
||||||
|
port->number,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline usbh_urbstatus_t usbhhubClearFeatureHub(USBHDriver *host, uint8_t feature) {
|
||||||
|
return usbhhubControlRequest(host,
|
||||||
|
USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_DEVICE,
|
||||||
|
USBH_REQ_CLEAR_FEATURE,
|
||||||
|
feature,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline usbh_urbstatus_t usbhhubSetFeaturePort(usbh_port_t *port, uint8_t feature) {
|
||||||
|
return usbhhubControlRequest(port->device.host,
|
||||||
|
USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_OTHER,
|
||||||
|
USBH_REQ_SET_FEATURE,
|
||||||
|
feature,
|
||||||
|
port->number,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* USBH_HUB_H_ */
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||||
|
Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef USBH_MSD_H_
|
||||||
|
#define USBH_MSD_H_
|
||||||
|
|
||||||
|
#include "usbh.h"
|
||||||
|
|
||||||
|
#if HAL_USE_USBH && HAL_USBH_USE_MSD
|
||||||
|
|
||||||
|
/* TODO:
|
||||||
|
*
|
||||||
|
* - Implement of conditional compilation of multiple-luns per instance.
|
||||||
|
* - Implement error checking and recovery when commands fail.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver pre-compile time settings. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Derived constants and error checks. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver data structures and types. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
#define _usbhmsd_driver_methods \
|
||||||
|
_base_block_device_methods
|
||||||
|
|
||||||
|
struct USBHMassStorageDriverVMT {
|
||||||
|
_usbhmsd_driver_methods
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct USBHMassStorageLUNDriver USBHMassStorageLUNDriver;
|
||||||
|
typedef struct USBHMassStorageDriver USBHMassStorageDriver;
|
||||||
|
|
||||||
|
struct USBHMassStorageLUNDriver {
|
||||||
|
/* inherited from abstract block driver */
|
||||||
|
const struct USBHMassStorageDriverVMT *vmt;
|
||||||
|
_base_block_device_data
|
||||||
|
|
||||||
|
BlockDeviceInfo info;
|
||||||
|
USBHMassStorageDriver *msdp;
|
||||||
|
|
||||||
|
USBHMassStorageLUNDriver *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct USBHMassStorageDriver {
|
||||||
|
/* inherited from abstract class driver */
|
||||||
|
_usbh_base_classdriver_data
|
||||||
|
|
||||||
|
/* for LUN request serialization, can be removed
|
||||||
|
* if the driver is configured to support only one LUN
|
||||||
|
* per USBHMassStorageDriver instance */
|
||||||
|
mutex_t mtx;
|
||||||
|
|
||||||
|
usbh_ep_t epin;
|
||||||
|
usbh_ep_t epout;
|
||||||
|
uint8_t ifnum;
|
||||||
|
uint8_t max_lun;
|
||||||
|
uint32_t tag;
|
||||||
|
|
||||||
|
USBHMassStorageLUNDriver *luns;
|
||||||
|
} USBHMassStorageDriver;
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver macros. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* External declarations. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
extern USBHMassStorageLUNDriver MSBLKD[HAL_USBHMSD_MAX_LUNS];
|
||||||
|
extern USBHMassStorageDriver USBHMSD[HAL_USBHMSD_MAX_INSTANCES];
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/* Mass Storage Driver */
|
||||||
|
void usbhmsdObjectInit(USBHMassStorageDriver *msdp);
|
||||||
|
|
||||||
|
/* Mass Storage LUN Driver (block driver) */
|
||||||
|
void usbhmsdLUNObjectInit(USBHMassStorageLUNDriver *lunp);
|
||||||
|
void usbhmsdLUNStart(USBHMassStorageLUNDriver *lunp);
|
||||||
|
void usbhmsdLUNStop(USBHMassStorageLUNDriver *lunp);
|
||||||
|
bool usbhmsdLUNConnect(USBHMassStorageLUNDriver *lunp);
|
||||||
|
bool usbhmsdLUNDisconnect(USBHMassStorageLUNDriver *lunp);
|
||||||
|
bool usbhmsdLUNRead(USBHMassStorageLUNDriver *lunp, uint32_t startblk,
|
||||||
|
uint8_t *buffer, uint32_t n);
|
||||||
|
bool usbhmsdLUNWrite(USBHMassStorageLUNDriver *lunp, uint32_t startblk,
|
||||||
|
const uint8_t *buffer, uint32_t n);
|
||||||
|
bool usbhmsdLUNSync(USBHMassStorageLUNDriver *lunp);
|
||||||
|
bool usbhmsdLUNGetInfo(USBHMassStorageLUNDriver *lunp, BlockDeviceInfo *bdip);
|
||||||
|
bool usbhmsdLUNIsInserted(USBHMassStorageLUNDriver *lunp);
|
||||||
|
bool usbhmsdLUNIsProtected(USBHMassStorageLUNDriver *lunp);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* USBH_MSD_H_ */
|
|
@ -0,0 +1,148 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||||
|
Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef USBH_INTERNAL_H_
|
||||||
|
#define USBH_INTERNAL_H_
|
||||||
|
|
||||||
|
#include "usbh.h"
|
||||||
|
|
||||||
|
#if HAL_USE_USBH
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* These declarations are not part of the public API. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
#if HAL_USBH_USE_FTDI
|
||||||
|
extern const usbh_classdriverinfo_t usbhftdiClassDriverInfo;
|
||||||
|
#endif
|
||||||
|
#if HAL_USBH_USE_MSD
|
||||||
|
extern const usbh_classdriverinfo_t usbhmsdClassDriverInfo;
|
||||||
|
#endif
|
||||||
|
#if HAL_USBH_USE_UVC
|
||||||
|
extern const usbh_classdriverinfo_t usbhuvcClassDriverInfo;
|
||||||
|
#endif
|
||||||
|
#if HAL_USBH_USE_HUB
|
||||||
|
extern const usbh_classdriverinfo_t usbhhubClassDriverInfo;
|
||||||
|
void _usbhub_port_object_init(usbh_port_t *port, USBHDriver *usbh,
|
||||||
|
USBHHubDriver *hub, uint8_t number);
|
||||||
|
#else
|
||||||
|
void _usbhub_port_object_init(usbh_port_t *port, USBHDriver *usbh, uint8_t number);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void _usbh_port_disconnected(usbh_port_t *port);
|
||||||
|
void _usbh_urb_completeI(usbh_urb_t *urb, usbh_urbstatus_t status);
|
||||||
|
bool _usbh_urb_abortI(usbh_urb_t *urb, usbh_urbstatus_t status);
|
||||||
|
void _usbh_urb_abort_and_waitS(usbh_urb_t *urb, usbh_urbstatus_t status);
|
||||||
|
|
||||||
|
|
||||||
|
#define USBH_CLASSIN(type, req, value, index) \
|
||||||
|
(USBH_REQTYPE_IN | type | USBH_REQTYPE_CLASS), \
|
||||||
|
req, \
|
||||||
|
value, \
|
||||||
|
index
|
||||||
|
|
||||||
|
#define USBH_CLASSOUT(type, req, value, index) \
|
||||||
|
(USBH_REQTYPE_OUT | type | USBH_REQTYPE_CLASS), \
|
||||||
|
req, \
|
||||||
|
value, \
|
||||||
|
index
|
||||||
|
|
||||||
|
#define USBH_STANDARDIN(type, req, value, index) \
|
||||||
|
(USBH_REQTYPE_IN | type | USBH_REQTYPE_STANDARD), \
|
||||||
|
req, \
|
||||||
|
value, \
|
||||||
|
index
|
||||||
|
|
||||||
|
#define USBH_STANDARDOUT(type, req, value, index) \
|
||||||
|
(USBH_REQTYPE_OUT | type | USBH_REQTYPE_STANDARD), \
|
||||||
|
req, \
|
||||||
|
value, \
|
||||||
|
index
|
||||||
|
|
||||||
|
|
||||||
|
#define USBH_PID_DATA0 0
|
||||||
|
#define USBH_PID_DATA2 1
|
||||||
|
#define USBH_PID_DATA1 2
|
||||||
|
#define USBH_PID_MDATA 3
|
||||||
|
#define USBH_PID_SETUP 3
|
||||||
|
|
||||||
|
|
||||||
|
/* GetBusState and SetHubDescriptor are optional, omitted */
|
||||||
|
#define ClearHubFeature (((USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_DEVICE) << 8) \
|
||||||
|
| USBH_REQ_CLEAR_FEATURE)
|
||||||
|
#define SetHubFeature (((USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_DEVICE) << 8) \
|
||||||
|
| USBH_REQ_SET_FEATURE)
|
||||||
|
#define ClearPortFeature (((USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_OTHER) << 8) \
|
||||||
|
| USBH_REQ_CLEAR_FEATURE)
|
||||||
|
#define SetPortFeature (((USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_OTHER) << 8) \
|
||||||
|
| USBH_REQ_SET_FEATURE)
|
||||||
|
#define GetHubDescriptor (((USBH_REQTYPE_IN | USBH_REQTYPE_CLASS | USBH_REQTYPE_DEVICE) << 8) \
|
||||||
|
| USBH_REQ_GET_DESCRIPTOR)
|
||||||
|
#define GetHubStatus (((USBH_REQTYPE_IN | USBH_REQTYPE_CLASS | USBH_REQTYPE_DEVICE) << 8) \
|
||||||
|
| USBH_REQ_GET_STATUS)
|
||||||
|
#define GetPortStatus (((USBH_REQTYPE_IN | USBH_REQTYPE_CLASS | USBH_REQTYPE_OTHER) << 8) \
|
||||||
|
| USBH_REQ_GET_STATUS)
|
||||||
|
|
||||||
|
|
||||||
|
#define USBH_PORTSTATUS_CONNECTION 0x0001
|
||||||
|
#define USBH_PORTSTATUS_ENABLE 0x0002
|
||||||
|
#define USBH_PORTSTATUS_SUSPEND 0x0004
|
||||||
|
#define USBH_PORTSTATUS_OVERCURRENT 0x0008
|
||||||
|
#define USBH_PORTSTATUS_RESET 0x0010
|
||||||
|
/* bits 5 to 7 are reserved */
|
||||||
|
#define USBH_PORTSTATUS_POWER 0x0100
|
||||||
|
#define USBH_PORTSTATUS_LOW_SPEED 0x0200
|
||||||
|
#define USBH_PORTSTATUS_HIGH_SPEED 0x0400
|
||||||
|
#define USBH_PORTSTATUS_TEST 0x0800
|
||||||
|
#define USBH_PORTSTATUS_INDICATOR 0x1000
|
||||||
|
/* bits 13 to 15 are reserved */
|
||||||
|
|
||||||
|
#define USBH_PORTSTATUS_C_CONNECTION 0x0001
|
||||||
|
#define USBH_PORTSTATUS_C_ENABLE 0x0002
|
||||||
|
#define USBH_PORTSTATUS_C_SUSPEND 0x0004
|
||||||
|
#define USBH_PORTSTATUS_C_OVERCURRENT 0x0008
|
||||||
|
#define USBH_PORTSTATUS_C_RESET 0x0010
|
||||||
|
|
||||||
|
#define USBH_HUBSTATUS_C_HUB_LOCAL_POWER 0x0001
|
||||||
|
#define USBH_HUBSTATUS_C_HUB_OVER_CURRENT 0x0002
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Port feature numbers
|
||||||
|
* See USB 2.0 spec Table 11-17
|
||||||
|
*/
|
||||||
|
#define USBH_HUB_FEAT_C_HUB_LOCAL_POWER 0
|
||||||
|
#define USBH_HUB_FEAT_C_HUB_OVER_CURRENT 1
|
||||||
|
#define USBH_PORT_FEAT_CONNECTION 0
|
||||||
|
#define USBH_PORT_FEAT_ENABLE 1
|
||||||
|
#define USBH_PORT_FEAT_SUSPEND 2
|
||||||
|
#define USBH_PORT_FEAT_OVERCURRENT 3
|
||||||
|
#define USBH_PORT_FEAT_RESET 4
|
||||||
|
#define USBH_PORT_FEAT_POWER 8
|
||||||
|
#define USBH_PORT_FEAT_LOWSPEED 9
|
||||||
|
#define USBH_PORT_FEAT_C_CONNECTION 16
|
||||||
|
#define USBH_PORT_FEAT_C_ENABLE 17
|
||||||
|
#define USBH_PORT_FEAT_C_SUSPEND 18
|
||||||
|
#define USBH_PORT_FEAT_C_OVERCURRENT 19
|
||||||
|
#define USBH_PORT_FEAT_C_RESET 20
|
||||||
|
#define USBH_PORT_FEAT_TEST 21
|
||||||
|
#define USBH_PORT_FEAT_INDICATOR 22
|
||||||
|
|
||||||
|
#define sizeof_array(x) (sizeof(x)/sizeof(*(x)))
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* USBH_INTERNAL_H_ */
|
|
@ -0,0 +1,598 @@
|
||||||
|
#ifndef USBH_LIST_H_
|
||||||
|
#define USBH_LIST_H_
|
||||||
|
|
||||||
|
/* TODO: re-write this file; stolen from linux */
|
||||||
|
|
||||||
|
#ifndef offsetof
|
||||||
|
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define container_of(ptr, type, member) ((type *)(void *)((char *)(ptr) - offsetof(type, member)))
|
||||||
|
#ifndef container_of
|
||||||
|
#define container_of(ptr, type, member) ({ \
|
||||||
|
const typeof(((type *)0)->member) * __mptr = (ptr); \
|
||||||
|
(type *)((char *)__mptr - offsetof(type, member)); })
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple doubly linked list implementation.
|
||||||
|
*
|
||||||
|
* Some of the internal functions ("__xxx") are useful when
|
||||||
|
* manipulating whole lists rather than single entries, as
|
||||||
|
* sometimes we already know the next/prev entries and we can
|
||||||
|
* generate better code by using them directly rather than
|
||||||
|
* using the generic single-entry routines.
|
||||||
|
*/
|
||||||
|
struct list_head {
|
||||||
|
struct list_head *next, *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||||
|
|
||||||
|
#define LIST_HEAD(name) \
|
||||||
|
struct list_head name = LIST_HEAD_INIT(name)
|
||||||
|
|
||||||
|
static inline void INIT_LIST_HEAD(struct list_head *list)
|
||||||
|
{
|
||||||
|
list->next = list;
|
||||||
|
list->prev = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert a new entry between two known consecutive entries.
|
||||||
|
*
|
||||||
|
* This is only for internal list manipulation where we know
|
||||||
|
* the prev/next entries already!
|
||||||
|
*/
|
||||||
|
#ifndef CONFIG_DEBUG_LIST
|
||||||
|
static inline void __list_add(struct list_head *new,
|
||||||
|
struct list_head *prev,
|
||||||
|
struct list_head *next)
|
||||||
|
{
|
||||||
|
next->prev = new;
|
||||||
|
new->next = next;
|
||||||
|
new->prev = prev;
|
||||||
|
prev->next = new;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
extern void __list_add(struct list_head *new,
|
||||||
|
struct list_head *prev,
|
||||||
|
struct list_head *next);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_add - add a new entry
|
||||||
|
* @new: new entry to be added
|
||||||
|
* @head: list head to add it after
|
||||||
|
*
|
||||||
|
* Insert a new entry after the specified head.
|
||||||
|
* This is good for implementing stacks.
|
||||||
|
*/
|
||||||
|
static inline void list_add(struct list_head *new, struct list_head *head)
|
||||||
|
{
|
||||||
|
__list_add(new, head, head->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_add_tail - add a new entry
|
||||||
|
* @new: new entry to be added
|
||||||
|
* @head: list head to add it before
|
||||||
|
*
|
||||||
|
* Insert a new entry before the specified head.
|
||||||
|
* This is useful for implementing queues.
|
||||||
|
*/
|
||||||
|
static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
||||||
|
{
|
||||||
|
__list_add(new, head->prev, head);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete a list entry by making the prev/next entries
|
||||||
|
* point to each other.
|
||||||
|
*
|
||||||
|
* This is only for internal list manipulation where we know
|
||||||
|
* the prev/next entries already!
|
||||||
|
*/
|
||||||
|
static inline void __list_del(struct list_head * prev, struct list_head * next)
|
||||||
|
{
|
||||||
|
next->prev = prev;
|
||||||
|
prev->next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_del - deletes entry from list.
|
||||||
|
* @entry: the element to delete from the list.
|
||||||
|
* Note: list_empty() on entry does not return true after this, the entry is
|
||||||
|
* in an undefined state.
|
||||||
|
*/
|
||||||
|
#ifndef CONFIG_DEBUG_LIST
|
||||||
|
static inline void __list_del_entry(struct list_head *entry)
|
||||||
|
{
|
||||||
|
__list_del(entry->prev, entry->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void list_del(struct list_head *entry)
|
||||||
|
{
|
||||||
|
__list_del(entry->prev, entry->next);
|
||||||
|
// entry->next = LIST_POISON1;
|
||||||
|
// entry->prev = LIST_POISON2;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
extern void __list_del_entry(struct list_head *entry);
|
||||||
|
extern void list_del(struct list_head *entry);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_replace - replace old entry by new one
|
||||||
|
* @old : the element to be replaced
|
||||||
|
* @new : the new element to insert
|
||||||
|
*
|
||||||
|
* If @old was empty, it will be overwritten.
|
||||||
|
*/
|
||||||
|
static inline void list_replace(struct list_head *old,
|
||||||
|
struct list_head *new)
|
||||||
|
{
|
||||||
|
new->next = old->next;
|
||||||
|
new->next->prev = new;
|
||||||
|
new->prev = old->prev;
|
||||||
|
new->prev->next = new;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void list_replace_init(struct list_head *old,
|
||||||
|
struct list_head *new)
|
||||||
|
{
|
||||||
|
list_replace(old, new);
|
||||||
|
INIT_LIST_HEAD(old);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_del_init - deletes entry from list and reinitialize it.
|
||||||
|
* @entry: the element to delete from the list.
|
||||||
|
*/
|
||||||
|
static inline void list_del_init(struct list_head *entry)
|
||||||
|
{
|
||||||
|
__list_del_entry(entry);
|
||||||
|
INIT_LIST_HEAD(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_move - delete from one list and add as another's head
|
||||||
|
* @list: the entry to move
|
||||||
|
* @head: the head that will precede our entry
|
||||||
|
*/
|
||||||
|
static inline void list_move(struct list_head *list, struct list_head *head)
|
||||||
|
{
|
||||||
|
__list_del_entry(list);
|
||||||
|
list_add(list, head);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_move_tail - delete from one list and add as another's tail
|
||||||
|
* @list: the entry to move
|
||||||
|
* @head: the head that will follow our entry
|
||||||
|
*/
|
||||||
|
static inline void list_move_tail(struct list_head *list,
|
||||||
|
struct list_head *head)
|
||||||
|
{
|
||||||
|
__list_del_entry(list);
|
||||||
|
list_add_tail(list, head);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_is_last - tests whether @list is the last entry in list @head
|
||||||
|
* @list: the entry to test
|
||||||
|
* @head: the head of the list
|
||||||
|
*/
|
||||||
|
static inline int list_is_last(const struct list_head *list,
|
||||||
|
const struct list_head *head)
|
||||||
|
{
|
||||||
|
return list->next == head;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_empty - tests whether a list is empty
|
||||||
|
* @head: the list to test.
|
||||||
|
*/
|
||||||
|
static inline int list_empty(const struct list_head *head)
|
||||||
|
{
|
||||||
|
return head->next == head;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_empty_careful - tests whether a list is empty and not being modified
|
||||||
|
* @head: the list to test
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* tests whether a list is empty _and_ checks that no other CPU might be
|
||||||
|
* in the process of modifying either member (next or prev)
|
||||||
|
*
|
||||||
|
* NOTE: using list_empty_careful() without synchronization
|
||||||
|
* can only be safe if the only activity that can happen
|
||||||
|
* to the list entry is list_del_init(). Eg. it cannot be used
|
||||||
|
* if another CPU could re-list_add() it.
|
||||||
|
*/
|
||||||
|
static inline int list_empty_careful(const struct list_head *head)
|
||||||
|
{
|
||||||
|
struct list_head *next = head->next;
|
||||||
|
return (next == head) && (next == head->prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_rotate_left - rotate the list to the left
|
||||||
|
* @head: the head of the list
|
||||||
|
*/
|
||||||
|
static inline void list_rotate_left(struct list_head *head)
|
||||||
|
{
|
||||||
|
struct list_head *first;
|
||||||
|
|
||||||
|
if (!list_empty(head)) {
|
||||||
|
first = head->next;
|
||||||
|
list_move_tail(first, head);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_is_singular - tests whether a list has just one entry.
|
||||||
|
* @head: the list to test.
|
||||||
|
*/
|
||||||
|
static inline int list_is_singular(const struct list_head *head)
|
||||||
|
{
|
||||||
|
return !list_empty(head) && (head->next == head->prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void __list_cut_position(struct list_head *list,
|
||||||
|
struct list_head *head, struct list_head *entry)
|
||||||
|
{
|
||||||
|
struct list_head *new_first = entry->next;
|
||||||
|
list->next = head->next;
|
||||||
|
list->next->prev = list;
|
||||||
|
list->prev = entry;
|
||||||
|
entry->next = list;
|
||||||
|
head->next = new_first;
|
||||||
|
new_first->prev = head;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_cut_position - cut a list into two
|
||||||
|
* @list: a new list to add all removed entries
|
||||||
|
* @head: a list with entries
|
||||||
|
* @entry: an entry within head, could be the head itself
|
||||||
|
* and if so we won't cut the list
|
||||||
|
*
|
||||||
|
* This helper moves the initial part of @head, up to and
|
||||||
|
* including @entry, from @head to @list. You should
|
||||||
|
* pass on @entry an element you know is on @head. @list
|
||||||
|
* should be an empty list or a list you do not care about
|
||||||
|
* losing its data.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static inline void list_cut_position(struct list_head *list,
|
||||||
|
struct list_head *head, struct list_head *entry)
|
||||||
|
{
|
||||||
|
if (list_empty(head))
|
||||||
|
return;
|
||||||
|
if (list_is_singular(head) &&
|
||||||
|
(head->next != entry && head != entry))
|
||||||
|
return;
|
||||||
|
if (entry == head)
|
||||||
|
INIT_LIST_HEAD(list);
|
||||||
|
else
|
||||||
|
__list_cut_position(list, head, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void __list_splice(const struct list_head *list,
|
||||||
|
struct list_head *prev,
|
||||||
|
struct list_head *next)
|
||||||
|
{
|
||||||
|
struct list_head *first = list->next;
|
||||||
|
struct list_head *last = list->prev;
|
||||||
|
|
||||||
|
first->prev = prev;
|
||||||
|
prev->next = first;
|
||||||
|
|
||||||
|
last->next = next;
|
||||||
|
next->prev = last;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_splice - join two lists, this is designed for stacks
|
||||||
|
* @list: the new list to add.
|
||||||
|
* @head: the place to add it in the first list.
|
||||||
|
*/
|
||||||
|
static inline void list_splice(const struct list_head *list,
|
||||||
|
struct list_head *head)
|
||||||
|
{
|
||||||
|
if (!list_empty(list))
|
||||||
|
__list_splice(list, head, head->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_splice_tail - join two lists, each list being a queue
|
||||||
|
* @list: the new list to add.
|
||||||
|
* @head: the place to add it in the first list.
|
||||||
|
*/
|
||||||
|
static inline void list_splice_tail(struct list_head *list,
|
||||||
|
struct list_head *head)
|
||||||
|
{
|
||||||
|
if (!list_empty(list))
|
||||||
|
__list_splice(list, head->prev, head);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_splice_init - join two lists and reinitialise the emptied list.
|
||||||
|
* @list: the new list to add.
|
||||||
|
* @head: the place to add it in the first list.
|
||||||
|
*
|
||||||
|
* The list at @list is reinitialised
|
||||||
|
*/
|
||||||
|
static inline void list_splice_init(struct list_head *list,
|
||||||
|
struct list_head *head)
|
||||||
|
{
|
||||||
|
if (!list_empty(list)) {
|
||||||
|
__list_splice(list, head, head->next);
|
||||||
|
INIT_LIST_HEAD(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_splice_tail_init - join two lists and reinitialise the emptied list
|
||||||
|
* @list: the new list to add.
|
||||||
|
* @head: the place to add it in the first list.
|
||||||
|
*
|
||||||
|
* Each of the lists is a queue.
|
||||||
|
* The list at @list is reinitialised
|
||||||
|
*/
|
||||||
|
static inline void list_splice_tail_init(struct list_head *list,
|
||||||
|
struct list_head *head)
|
||||||
|
{
|
||||||
|
if (!list_empty(list)) {
|
||||||
|
__list_splice(list, head->prev, head);
|
||||||
|
INIT_LIST_HEAD(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_entry - get the struct for this entry
|
||||||
|
* @ptr: the &struct list_head pointer.
|
||||||
|
* @type: the type of the struct this is embedded in.
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*/
|
||||||
|
#define list_entry(ptr, type, member) \
|
||||||
|
container_of(ptr, type, member)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_first_entry - get the first element from a list
|
||||||
|
* @ptr: the list head to take the element from.
|
||||||
|
* @type: the type of the struct this is embedded in.
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*
|
||||||
|
* Note, that list is expected to be not empty.
|
||||||
|
*/
|
||||||
|
#define list_first_entry(ptr, type, member) \
|
||||||
|
list_entry((ptr)->next, type, member)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_last_entry - get the last element from a list
|
||||||
|
* @ptr: the list head to take the element from.
|
||||||
|
* @type: the type of the struct this is embedded in.
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*
|
||||||
|
* Note, that list is expected to be not empty.
|
||||||
|
*/
|
||||||
|
#define list_last_entry(ptr, type, member) \
|
||||||
|
list_entry((ptr)->prev, type, member)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_first_entry_or_null - get the first element from a list
|
||||||
|
* @ptr: the list head to take the element from.
|
||||||
|
* @type: the type of the struct this is embedded in.
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*
|
||||||
|
* Note that if the list is empty, it returns NULL.
|
||||||
|
*/
|
||||||
|
#define list_first_entry_or_null(ptr, type, member) \
|
||||||
|
(!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_next_entry - get the next element in list
|
||||||
|
* @pos: the type * to cursor
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*/
|
||||||
|
#define list_next_entry(pos, type, member) \
|
||||||
|
list_entry((pos)->member.next, type, member)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_prev_entry - get the prev element in list
|
||||||
|
* @pos: the type * to cursor
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*/
|
||||||
|
#define list_prev_entry(pos, type, member) \
|
||||||
|
list_entry((pos)->member.prev, type, member)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each - iterate over a list
|
||||||
|
* @pos: the &struct list_head to use as a loop cursor.
|
||||||
|
* @head: the head for your list.
|
||||||
|
*/
|
||||||
|
#define list_for_each(pos, head) \
|
||||||
|
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_prev - iterate over a list backwards
|
||||||
|
* @pos: the &struct list_head to use as a loop cursor.
|
||||||
|
* @head: the head for your list.
|
||||||
|
*/
|
||||||
|
#define list_for_each_prev(pos, head) \
|
||||||
|
for (pos = (head)->prev; pos != (head); pos = pos->prev)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_safe - iterate over a list safe against removal of list entry
|
||||||
|
* @pos: the &struct list_head to use as a loop cursor.
|
||||||
|
* @n: another &struct list_head to use as temporary storage
|
||||||
|
* @head: the head for your list.
|
||||||
|
*/
|
||||||
|
#define list_for_each_safe(pos, n, head) \
|
||||||
|
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||||
|
pos = n, n = pos->next)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
|
||||||
|
* @pos: the &struct list_head to use as a loop cursor.
|
||||||
|
* @n: another &struct list_head to use as temporary storage
|
||||||
|
* @head: the head for your list.
|
||||||
|
*/
|
||||||
|
#define list_for_each_prev_safe(pos, n, head) \
|
||||||
|
for (pos = (head)->prev, n = pos->prev; \
|
||||||
|
pos != (head); \
|
||||||
|
pos = n, n = pos->prev)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_entry - iterate over list of given type
|
||||||
|
* @pos: the type * to use as a loop cursor.
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*/
|
||||||
|
#define list_for_each_entry(pos, type, head, member) \
|
||||||
|
for (pos = list_first_entry(head, type, member); \
|
||||||
|
&pos->member != (head); \
|
||||||
|
pos = list_next_entry(pos, type, member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_entry_reverse - iterate backwards over list of given type.
|
||||||
|
* @pos: the type * to use as a loop cursor.
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*/
|
||||||
|
#define list_for_each_entry_reverse(pos, type, head, member) \
|
||||||
|
for (pos = list_last_entry(head, type, member); \
|
||||||
|
&pos->member != (head); \
|
||||||
|
pos = list_prev_entry(pos, type, member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
|
||||||
|
* @pos: the type * to use as a start point
|
||||||
|
* @head: the head of the list
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*
|
||||||
|
* Prepares a pos entry for use as a start point in list_for_each_entry_continue().
|
||||||
|
*/
|
||||||
|
#define list_prepare_entry(pos, type, head, member) \
|
||||||
|
((pos) ? : list_entry(head, type, member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_entry_continue - continue iteration over list of given type
|
||||||
|
* @pos: the type * to use as a loop cursor.
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*
|
||||||
|
* Continue to iterate over list of given type, continuing after
|
||||||
|
* the current position.
|
||||||
|
*/
|
||||||
|
#define list_for_each_entry_continue(pos, type, head, member) \
|
||||||
|
for (pos = list_next_entry(pos, type, member); \
|
||||||
|
&pos->member != (head); \
|
||||||
|
pos = list_next_entry(pos, type, member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_entry_continue_reverse - iterate backwards from the given point
|
||||||
|
* @pos: the type * to use as a loop cursor.
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*
|
||||||
|
* Start to iterate over list of given type backwards, continuing after
|
||||||
|
* the current position.
|
||||||
|
*/
|
||||||
|
#define list_for_each_entry_continue_reverse(pos, type, head, member) \
|
||||||
|
for (pos = list_prev_entry(pos, type, member); \
|
||||||
|
&pos->member != (head); \
|
||||||
|
pos = list_prev_entry(pos, type, member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_entry_from - iterate over list of given type from the current point
|
||||||
|
* @pos: the type * to use as a loop cursor.
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*
|
||||||
|
* Iterate over list of given type, continuing from current position.
|
||||||
|
*/
|
||||||
|
#define list_for_each_entry_from(pos, type, head, member) \
|
||||||
|
for (; &pos->member != (head); \
|
||||||
|
pos = list_next_entry(pos, type, member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||||
|
* @pos: the type * to use as a loop cursor.
|
||||||
|
* @n: another type * to use as temporary storage
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*/
|
||||||
|
#define list_for_each_entry_safe(pos, type, n, head, member) \
|
||||||
|
for (pos = list_first_entry(head, type, member), \
|
||||||
|
n = list_next_entry(pos, type, member); \
|
||||||
|
&pos->member != (head); \
|
||||||
|
pos = n, n = list_next_entry(n, type, member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_entry_safe_continue - continue list iteration safe against removal
|
||||||
|
* @pos: the type * to use as a loop cursor.
|
||||||
|
* @n: another type * to use as temporary storage
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*
|
||||||
|
* Iterate over list of given type, continuing after current point,
|
||||||
|
* safe against removal of list entry.
|
||||||
|
*/
|
||||||
|
#define list_for_each_entry_safe_continue(pos, type, n, head, member) \
|
||||||
|
for (pos = list_next_entry(pos, type, member), \
|
||||||
|
n = list_next_entry(pos, type, member); \
|
||||||
|
&pos->member != (head); \
|
||||||
|
pos = n, n = list_next_entry(n, type, member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_entry_safe_from - iterate over list from current point safe against removal
|
||||||
|
* @pos: the type * to use as a loop cursor.
|
||||||
|
* @n: another type * to use as temporary storage
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*
|
||||||
|
* Iterate over list of given type from current point, safe against
|
||||||
|
* removal of list entry.
|
||||||
|
*/
|
||||||
|
#define list_for_each_entry_safe_from(pos, type, n, head, member) \
|
||||||
|
for (n = list_next_entry(pos, type, member); \
|
||||||
|
&pos->member != (head); \
|
||||||
|
pos = n, n = list_next_entry(n, type, member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
|
||||||
|
* @pos: the type * to use as a loop cursor.
|
||||||
|
* @n: another type * to use as temporary storage
|
||||||
|
* @head: the head for your list.
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*
|
||||||
|
* Iterate backwards over list of given type, safe against removal
|
||||||
|
* of list entry.
|
||||||
|
*/
|
||||||
|
#define list_for_each_entry_safe_reverse(pos, type, n, head, member) \
|
||||||
|
for (pos = list_last_entry(head, type, member), \
|
||||||
|
n = list_prev_entry(pos, type, member); \
|
||||||
|
&pos->member != (head); \
|
||||||
|
pos = n, n = list_prev_entry(n, type, member))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list_safe_reset_next - reset a stale list_for_each_entry_safe loop
|
||||||
|
* @pos: the loop cursor used in the list_for_each_entry_safe loop
|
||||||
|
* @n: temporary storage used in list_for_each_entry_safe
|
||||||
|
* @member: the name of the list_head within the struct.
|
||||||
|
*
|
||||||
|
* list_safe_reset_next is not safe to use in general if the list may be
|
||||||
|
* modified concurrently (eg. the lock is dropped in the loop body). An
|
||||||
|
* exception to this is if the cursor element (pos) is pinned in the list,
|
||||||
|
* and list_safe_reset_next is called after re-taking the lock and before
|
||||||
|
* completing the current iteration of the loop body.
|
||||||
|
*/
|
||||||
|
#define list_safe_reset_next(pos, type, n, member) \
|
||||||
|
n = list_next_entry(pos, type, member)
|
||||||
|
|
||||||
|
#endif /* USBH_LIST_H_ */
|
|
@ -0,0 +1,929 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file stm32_otg.h
|
||||||
|
* @brief STM32 OTG registers layout header.
|
||||||
|
*
|
||||||
|
* @addtogroup USB
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _STM32_OTG_H_
|
||||||
|
#define _STM32_OTG_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Number of the implemented endpoints in OTG_FS.
|
||||||
|
* @details This value does not include the endpoint 0 that is always present.
|
||||||
|
*/
|
||||||
|
#define STM32_OTG1_ENDOPOINTS_NUMBER 3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Number of the implemented endpoints in OTG_HS.
|
||||||
|
* @details This value does not include the endpoint 0 that is always present.
|
||||||
|
*/
|
||||||
|
#define STM32_OTG2_ENDOPOINTS_NUMBER 5
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief OTG_FS FIFO memory size in words.
|
||||||
|
*/
|
||||||
|
#define STM32_OTG1_FIFO_MEM_SIZE 320
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief OTG_HS FIFO memory size in words.
|
||||||
|
*/
|
||||||
|
#define STM32_OTG2_FIFO_MEM_SIZE 1024
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Host channel registers group.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
volatile uint32_t HCCHAR; /**< @brief Host channel characteristics
|
||||||
|
register. */
|
||||||
|
volatile uint32_t resvd8;
|
||||||
|
volatile uint32_t HCINT; /**< @brief Host channel interrupt register.*/
|
||||||
|
volatile uint32_t HCINTMSK; /**< @brief Host channel interrupt mask
|
||||||
|
register. */
|
||||||
|
volatile uint32_t HCTSIZ; /**< @brief Host channel transfer size
|
||||||
|
register. */
|
||||||
|
volatile uint32_t resvd14;
|
||||||
|
volatile uint32_t resvd18;
|
||||||
|
volatile uint32_t resvd1c;
|
||||||
|
} stm32_otg_host_chn_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Device input endpoint registers group.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
volatile uint32_t DIEPCTL; /**< @brief Device control IN endpoint
|
||||||
|
control register. */
|
||||||
|
volatile uint32_t resvd4;
|
||||||
|
volatile uint32_t DIEPINT; /**< @brief Device IN endpoint interrupt
|
||||||
|
register. */
|
||||||
|
volatile uint32_t resvdC;
|
||||||
|
volatile uint32_t DIEPTSIZ; /**< @brief Device IN endpoint transfer size
|
||||||
|
register. */
|
||||||
|
volatile uint32_t resvd14;
|
||||||
|
volatile uint32_t DTXFSTS; /**< @brief Device IN endpoint transmit FIFO
|
||||||
|
status register. */
|
||||||
|
volatile uint32_t resvd1C;
|
||||||
|
} stm32_otg_in_ep_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Device output endpoint registers group.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
volatile uint32_t DOEPCTL; /**< @brief Device control OUT endpoint
|
||||||
|
control register. */
|
||||||
|
volatile uint32_t resvd4;
|
||||||
|
volatile uint32_t DOEPINT; /**< @brief Device OUT endpoint interrupt
|
||||||
|
register. */
|
||||||
|
volatile uint32_t resvdC;
|
||||||
|
volatile uint32_t DOEPTSIZ; /**< @brief Device OUT endpoint transfer
|
||||||
|
size register. */
|
||||||
|
volatile uint32_t resvd14;
|
||||||
|
volatile uint32_t resvd18;
|
||||||
|
volatile uint32_t resvd1C;
|
||||||
|
} stm32_otg_out_ep_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief USB registers memory map.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
volatile uint32_t GOTGCTL; /**< @brief OTG control and status register.*/
|
||||||
|
volatile uint32_t GOTGINT; /**< @brief OTG interrupt register. */
|
||||||
|
volatile uint32_t GAHBCFG; /**< @brief AHB configuration register. */
|
||||||
|
volatile uint32_t GUSBCFG; /**< @brief USB configuration register. */
|
||||||
|
volatile uint32_t GRSTCTL; /**< @brief Reset register size. */
|
||||||
|
volatile uint32_t GINTSTS; /**< @brief Interrupt register. */
|
||||||
|
volatile uint32_t GINTMSK; /**< @brief Interrupt mask register. */
|
||||||
|
volatile uint32_t GRXSTSR; /**< @brief Receive status debug read
|
||||||
|
register. */
|
||||||
|
volatile uint32_t GRXSTSP; /**< @brief Receive status read/pop
|
||||||
|
register. */
|
||||||
|
volatile uint32_t GRXFSIZ; /**< @brief Receive FIFO size register. */
|
||||||
|
volatile uint32_t DIEPTXF0; /**< @brief Endpoint 0 transmit FIFO size
|
||||||
|
register. */
|
||||||
|
volatile uint32_t HNPTXSTS; /**< @brief Non-periodic transmit FIFO/queue
|
||||||
|
status register. */
|
||||||
|
volatile uint32_t resvd30;
|
||||||
|
volatile uint32_t resvd34;
|
||||||
|
volatile uint32_t GCCFG; /**< @brief General core configuration. */
|
||||||
|
volatile uint32_t CID; /**< @brief Core ID register. */
|
||||||
|
volatile uint32_t resvd58[48];
|
||||||
|
volatile uint32_t HPTXFSIZ; /**< @brief Host periodic transmit FIFO size
|
||||||
|
register. */
|
||||||
|
volatile uint32_t DIEPTXF[15];/**< @brief Device IN endpoint transmit FIFO
|
||||||
|
size registers. */
|
||||||
|
volatile uint32_t resvd140[176];
|
||||||
|
volatile uint32_t HCFG; /**< @brief Host configuration register. */
|
||||||
|
volatile uint32_t HFIR; /**< @brief Host frame interval register. */
|
||||||
|
volatile uint32_t HFNUM; /**< @brief Host frame number/frame time
|
||||||
|
Remaining register. */
|
||||||
|
volatile uint32_t resvd40C;
|
||||||
|
volatile uint32_t HPTXSTS; /**< @brief Host periodic transmit FIFO/queue
|
||||||
|
status register. */
|
||||||
|
volatile uint32_t HAINT; /**< @brief Host all channels interrupt
|
||||||
|
register. */
|
||||||
|
volatile uint32_t HAINTMSK; /**< @brief Host all channels interrupt mask
|
||||||
|
register. */
|
||||||
|
volatile uint32_t resvd41C[9];
|
||||||
|
volatile uint32_t HPRT; /**< @brief Host port control and status
|
||||||
|
register. */
|
||||||
|
volatile uint32_t resvd444[47];
|
||||||
|
stm32_otg_host_chn_t hc[16]; /**< @brief Host channels array. */
|
||||||
|
volatile uint32_t resvd700[64];
|
||||||
|
volatile uint32_t DCFG; /**< @brief Device configuration register. */
|
||||||
|
volatile uint32_t DCTL; /**< @brief Device control register. */
|
||||||
|
volatile uint32_t DSTS; /**< @brief Device status register. */
|
||||||
|
volatile uint32_t resvd80C;
|
||||||
|
volatile uint32_t DIEPMSK; /**< @brief Device IN endpoint common
|
||||||
|
interrupt mask register. */
|
||||||
|
volatile uint32_t DOEPMSK; /**< @brief Device OUT endpoint common
|
||||||
|
interrupt mask register. */
|
||||||
|
volatile uint32_t DAINT; /**< @brief Device all endpoints interrupt
|
||||||
|
register. */
|
||||||
|
volatile uint32_t DAINTMSK; /**< @brief Device all endpoints interrupt
|
||||||
|
mask register. */
|
||||||
|
volatile uint32_t resvd820;
|
||||||
|
volatile uint32_t resvd824;
|
||||||
|
volatile uint32_t DVBUSDIS; /**< @brief Device VBUS discharge time
|
||||||
|
register. */
|
||||||
|
volatile uint32_t DVBUSPULSE; /**< @brief Device VBUS pulsing time
|
||||||
|
register. */
|
||||||
|
volatile uint32_t resvd830;
|
||||||
|
volatile uint32_t DIEPEMPMSK; /**< @brief Device IN endpoint FIFO empty
|
||||||
|
interrupt mask register. */
|
||||||
|
volatile uint32_t resvd838;
|
||||||
|
volatile uint32_t resvd83C;
|
||||||
|
volatile uint32_t resvd840[16];
|
||||||
|
volatile uint32_t resvd880[16];
|
||||||
|
volatile uint32_t resvd8C0[16];
|
||||||
|
stm32_otg_in_ep_t ie[16]; /**< @brief Input endpoints. */
|
||||||
|
stm32_otg_out_ep_t oe[16]; /**< @brief Output endpoints. */
|
||||||
|
volatile uint32_t resvdD00[64];
|
||||||
|
volatile uint32_t PCGCCTL; /**< @brief Power and clock gating control
|
||||||
|
register. */
|
||||||
|
volatile uint32_t resvdE04[127];
|
||||||
|
volatile uint32_t FIFO[16][1024];
|
||||||
|
} stm32_otg_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name GOTGCTL register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define GOTGCTL_BSVLD (1U<<19) /**< B-Session Valid. */
|
||||||
|
#define GOTGCTL_ASVLD (1U<<18) /**< A-Session Valid. */
|
||||||
|
#define GOTGCTL_DBCT (1U<<17) /**< Long/Short debounce time. */
|
||||||
|
#define GOTGCTL_CIDSTS (1U<<16) /**< Connector ID status. */
|
||||||
|
#define GOTGCTL_EHEN (1U<<12)
|
||||||
|
#define GOTGCTL_DHNPEN (1U<<11) /**< Device HNP enabled. */
|
||||||
|
#define GOTGCTL_HSHNPEN (1U<<10) /**< Host Set HNP enable. */
|
||||||
|
#define GOTGCTL_HNPRQ (1U<<9) /**< HNP request. */
|
||||||
|
#define GOTGCTL_HNGSCS (1U<<8) /**< Host negotiation success. */
|
||||||
|
#define GOTGCTL_BVALOVAL (1U<<7)
|
||||||
|
#define GOTGCTL_BVALOEN (1U<<6)
|
||||||
|
#define GOTGCTL_AVALOVAL (1U<<5)
|
||||||
|
#define GOTGCTL_AVALOEN (1U<<4)
|
||||||
|
#define GOTGCTL_VBVALOVAL (1U<<3)
|
||||||
|
#define GOTGCTL_VBVALOEN (1U<<2)
|
||||||
|
#define GOTGCTL_SRQ (1U<<1) /**< Session request. */
|
||||||
|
#define GOTGCTL_SRQSCS (1U<<0) /**< Session request success. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name GOTGINT register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define GOTGINT_DBCDNE (1U<<19) /**< Debounce done. */
|
||||||
|
#define GOTGINT_ADTOCHG (1U<<18) /**< A-Device timeout change. */
|
||||||
|
#define GOTGINT_HNGDET (1U<<17) /**< Host negotiation detected. */
|
||||||
|
#define GOTGINT_HNSSCHG (1U<<9) /**< Host negotiation success
|
||||||
|
status change. */
|
||||||
|
#define GOTGINT_SRSSCHG (1U<<8) /**< Session request success
|
||||||
|
status change. */
|
||||||
|
#define GOTGINT_SEDET (1U<<2) /**< Session end detected. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name GAHBCFG register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define GAHBCFG_PTXFELVL (1U<<8) /**< Periodic TxFIFO empty
|
||||||
|
level. */
|
||||||
|
#define GAHBCFG_TXFELVL (1U<<7) /**< Non-periodic TxFIFO empty
|
||||||
|
level. */
|
||||||
|
#define GAHBCFG_DMAEN (1U<<5) /**< DMA enable (HS only). */
|
||||||
|
#define GAHBCFG_HBSTLEN_MASK (15U<<1) /**< Burst length/type mask (HS
|
||||||
|
only). */
|
||||||
|
#define GAHBCFG_HBSTLEN(n) ((n)<<1) /**< Burst length/type (HS
|
||||||
|
only). */
|
||||||
|
#define GAHBCFG_GINTMSK (1U<<0) /**< Global interrupt mask. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name GUSBCFG register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define GUSBCFG_CTXPKT (1U<<31) /**< Corrupt Tx packet. */
|
||||||
|
#define GUSBCFG_FDMOD (1U<<30) /**< Force Device Mode. */
|
||||||
|
#define GUSBCFG_FHMOD (1U<<29) /**< Force Host Mode. */
|
||||||
|
#define GUSBCFG_TRDT_MASK (15U<<10) /**< USB Turnaround time field
|
||||||
|
mask. */
|
||||||
|
#define GUSBCFG_TRDT(n) ((n)<<10) /**< USB Turnaround time field
|
||||||
|
value. */
|
||||||
|
#define GUSBCFG_HNPCAP (1U<<9) /**< HNP-Capable. */
|
||||||
|
#define GUSBCFG_SRPCAP (1U<<8) /**< SRP-Capable. */
|
||||||
|
#define GUSBCFG_PHYSEL (1U<<6) /**< USB 2.0 High-Speed PHY or
|
||||||
|
USB 1.1 Full-Speed serial
|
||||||
|
transceiver Select. */
|
||||||
|
#define GUSBCFG_TOCAL_MASK (7U<<0) /**< HS/FS timeout calibration
|
||||||
|
field mask. */
|
||||||
|
#define GUSBCFG_TOCAL(n) ((n)<<0) /**< HS/FS timeout calibration
|
||||||
|
field value. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name GRSTCTL register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define GRSTCTL_AHBIDL (1U<<31) /**< AHB Master Idle. */
|
||||||
|
#define GRSTCTL_TXFNUM_MASK (31U<<6) /**< TxFIFO number field mask. */
|
||||||
|
#define GRSTCTL_TXFNUM(n) ((n)<<6) /**< TxFIFO number field value. */
|
||||||
|
#define GRSTCTL_TXFFLSH (1U<<5) /**< TxFIFO flush. */
|
||||||
|
#define GRSTCTL_RXFFLSH (1U<<4) /**< RxFIFO flush. */
|
||||||
|
#define GRSTCTL_FCRST (1U<<2) /**< Host frame counter reset. */
|
||||||
|
#define GRSTCTL_HSRST (1U<<1) /**< HClk soft reset. */
|
||||||
|
#define GRSTCTL_CSRST (1U<<0) /**< Core soft reset. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name GINTSTS register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define GINTSTS_WKUPINT (1U<<31) /**< Resume/Remote wakeup
|
||||||
|
detected interrupt. */
|
||||||
|
#define GINTSTS_SRQINT (1U<<30) /**< Session request/New session
|
||||||
|
detected interrupt. */
|
||||||
|
#define GINTSTS_DISCINT (1U<<29) /**< Disconnect detected
|
||||||
|
interrupt. */
|
||||||
|
#define GINTSTS_CIDSCHG (1U<<28) /**< Connector ID status change.*/
|
||||||
|
#define GINTSTS_PTXFE (1U<<26) /**< Periodic TxFIFO empty. */
|
||||||
|
#define GINTSTS_HCINT (1U<<25) /**< Host channels interrupt. */
|
||||||
|
#define GINTSTS_HPRTINT (1U<<24) /**< Host port interrupt. */
|
||||||
|
#define GINTSTS_IPXFR (1U<<21) /**< Incomplete periodic
|
||||||
|
transfer. */
|
||||||
|
#define GINTSTS_IISOOXFR (1U<<21) /**< Incomplete isochronous OUT
|
||||||
|
transfer. */
|
||||||
|
#define GINTSTS_IISOIXFR (1U<<20) /**< Incomplete isochronous IN
|
||||||
|
transfer. */
|
||||||
|
#define GINTSTS_OEPINT (1U<<19) /**< OUT endpoints interrupt. */
|
||||||
|
#define GINTSTS_IEPINT (1U<<18) /**< IN endpoints interrupt. */
|
||||||
|
#define GINTSTS_EOPF (1U<<15) /**< End of periodic frame
|
||||||
|
interrupt. */
|
||||||
|
#define GINTSTS_ISOODRP (1U<<14) /**< Isochronous OUT packet
|
||||||
|
dropped interrupt. */
|
||||||
|
#define GINTSTS_ENUMDNE (1U<<13) /**< Enumeration done. */
|
||||||
|
#define GINTSTS_USBRST (1U<<12) /**< USB reset. */
|
||||||
|
#define GINTSTS_USBSUSP (1U<<11) /**< USB suspend. */
|
||||||
|
#define GINTSTS_ESUSP (1U<<10) /**< Early suspend. */
|
||||||
|
#define GINTSTS_GONAKEFF (1U<<7) /**< Global OUT NAK effective. */
|
||||||
|
#define GINTSTS_GINAKEFF (1U<<6) /**< Global IN non-periodic NAK
|
||||||
|
effective. */
|
||||||
|
#define GINTSTS_NPTXFE (1U<<5) /**< Non-periodic TxFIFO empty. */
|
||||||
|
#define GINTSTS_RXFLVL (1U<<4) /**< RxFIFO non-empty. */
|
||||||
|
#define GINTSTS_SOF (1U<<3) /**< Start of frame. */
|
||||||
|
#define GINTSTS_OTGINT (1U<<2) /**< OTG interrupt. */
|
||||||
|
#define GINTSTS_MMIS (1U<<1) /**< Mode Mismatch interrupt. */
|
||||||
|
#define GINTSTS_CMOD (1U<<0) /**< Current mode of operation. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name GINTMSK register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define GINTMSK_WKUM (1U<<31) /**< Resume/remote wakeup
|
||||||
|
detected interrupt mask. */
|
||||||
|
#define GINTMSK_SRQM (1U<<30) /**< Session request/New session
|
||||||
|
detected interrupt mask. */
|
||||||
|
#define GINTMSK_DISCM (1U<<29) /**< Disconnect detected
|
||||||
|
interrupt mask. */
|
||||||
|
#define GINTMSK_CIDSCHGM (1U<<28) /**< Connector ID status change
|
||||||
|
mask. */
|
||||||
|
#define GINTMSK_PTXFEM (1U<<26) /**< Periodic TxFIFO empty mask.*/
|
||||||
|
#define GINTMSK_HCM (1U<<25) /**< Host channels interrupt
|
||||||
|
mask. */
|
||||||
|
#define GINTMSK_HPRTM (1U<<24) /**< Host port interrupt mask. */
|
||||||
|
#define GINTMSK_IPXFRM (1U<<21) /**< Incomplete periodic
|
||||||
|
transfer mask. */
|
||||||
|
#define GINTMSK_IISOOXFRM (1U<<21) /**< Incomplete isochronous OUT
|
||||||
|
transfer mask. */
|
||||||
|
#define GINTMSK_IISOIXFRM (1U<<20) /**< Incomplete isochronous IN
|
||||||
|
transfer mask. */
|
||||||
|
#define GINTMSK_OEPM (1U<<19) /**< OUT endpoints interrupt
|
||||||
|
mask. */
|
||||||
|
#define GINTMSK_IEPM (1U<<18) /**< IN endpoints interrupt
|
||||||
|
mask. */
|
||||||
|
#define GINTMSK_EOPFM (1U<<15) /**< End of periodic frame
|
||||||
|
interrupt mask. */
|
||||||
|
#define GINTMSK_ISOODRPM (1U<<14) /**< Isochronous OUT packet
|
||||||
|
dropped interrupt mask. */
|
||||||
|
#define GINTMSK_ENUMDNEM (1U<<13) /**< Enumeration done mask. */
|
||||||
|
#define GINTMSK_USBRSTM (1U<<12) /**< USB reset mask. */
|
||||||
|
#define GINTMSK_USBSUSPM (1U<<11) /**< USB suspend mask. */
|
||||||
|
#define GINTMSK_ESUSPM (1U<<10) /**< Early suspend mask. */
|
||||||
|
#define GINTMSK_GONAKEFFM (1U<<7) /**< Global OUT NAK effective
|
||||||
|
mask. */
|
||||||
|
#define GINTMSK_GINAKEFFM (1U<<6) /**< Global non-periodic IN NAK
|
||||||
|
effective mask. */
|
||||||
|
#define GINTMSK_NPTXFEM (1U<<5) /**< Non-periodic TxFIFO empty
|
||||||
|
mask. */
|
||||||
|
#define GINTMSK_RXFLVLM (1U<<4) /**< Receive FIFO non-empty
|
||||||
|
mask. */
|
||||||
|
#define GINTMSK_SOFM (1U<<3) /**< Start of (micro)frame mask.*/
|
||||||
|
#define GINTMSK_OTGM (1U<<2) /**< OTG interrupt mask. */
|
||||||
|
#define GINTMSK_MMISM (1U<<1) /**< Mode Mismatch interrupt
|
||||||
|
mask. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name GRXSTSR register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define GRXSTSR_PKTSTS_MASK (15U<<17) /**< Packet status mask. */
|
||||||
|
#define GRXSTSR_PKTSTS(n) ((n)<<17) /**< Packet status value. */
|
||||||
|
#define GRXSTSR_OUT_GLOBAL_NAK GRXSTSR_PKTSTS(1)
|
||||||
|
#define GRXSTSR_OUT_DATA GRXSTSR_PKTSTS(2)
|
||||||
|
#define GRXSTSR_OUT_COMP GRXSTSR_PKTSTS(3)
|
||||||
|
#define GRXSTSR_SETUP_COMP GRXSTSR_PKTSTS(4)
|
||||||
|
#define GRXSTSR_SETUP_DATA GRXSTSR_PKTSTS(6)
|
||||||
|
#define GRXSTSR_DPID_MASK (3U<<15) /**< Data PID mask. */
|
||||||
|
#define GRXSTSR_DPID(n) ((n)<<15) /**< Data PID value. */
|
||||||
|
#define GRXSTSR_BCNT_MASK (0x7FF<<4) /**< Byte count mask. */
|
||||||
|
#define GRXSTSR_BCNT(n) ((n)<<4) /**< Byte count value. */
|
||||||
|
#define GRXSTSR_CHNUM_MASK (15U<<0) /**< Channel number mask. */
|
||||||
|
#define GRXSTSR_CHNUM(n) ((n)<<0) /**< Channel number value. */
|
||||||
|
#define GRXSTSR_EPNUM_MASK (15U<<0) /**< Endpoint number mask. */
|
||||||
|
#define GRXSTSR_EPNUM(n) ((n)<<0) /**< Endpoint number value. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name GRXSTSP register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define GRXSTSP_PKTSTS_MASK (15<<17) /**< Packet status mask. */
|
||||||
|
#define GRXSTSP_PKTSTS(n) ((n)<<17) /**< Packet status value. */
|
||||||
|
#define GRXSTSP_OUT_GLOBAL_NAK GRXSTSP_PKTSTS(1)
|
||||||
|
#define GRXSTSP_OUT_DATA GRXSTSP_PKTSTS(2)
|
||||||
|
#define GRXSTSP_OUT_COMP GRXSTSP_PKTSTS(3)
|
||||||
|
#define GRXSTSP_SETUP_COMP GRXSTSP_PKTSTS(4)
|
||||||
|
#define GRXSTSP_SETUP_DATA GRXSTSP_PKTSTS(6)
|
||||||
|
#define GRXSTSP_DPID_MASK (3U<<15) /**< Data PID mask. */
|
||||||
|
#define GRXSTSP_DPID(n) ((n)<<15) /**< Data PID value. */
|
||||||
|
#define GRXSTSP_BCNT_MASK (0x7FF<<4) /**< Byte count mask. */
|
||||||
|
#define GRXSTSP_BCNT_OFF 4 /**< Byte count offset. */
|
||||||
|
#define GRXSTSP_BCNT(n) ((n)<<4) /**< Byte count value. */
|
||||||
|
#define GRXSTSP_CHNUM_MASK (15U<<0) /**< Channel number mask. */
|
||||||
|
#define GRXSTSP_CHNUM(n) ((n)<<0) /**< Channel number value. */
|
||||||
|
#define GRXSTSP_EPNUM_MASK (15U<<0) /**< Endpoint number mask. */
|
||||||
|
#define GRXSTSP_EPNUM_OFF 0 /**< Endpoint number offset. */
|
||||||
|
#define GRXSTSP_EPNUM(n) ((n)<<0) /**< Endpoint number value. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name GRXFSIZ register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define GRXFSIZ_RXFD_MASK (0xFFFF<<0) /**< RxFIFO depth mask. */
|
||||||
|
#define GRXFSIZ_RXFD(n) ((n)<<0) /**< RxFIFO depth value. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name DIEPTXFx register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define DIEPTXF_INEPTXFD_MASK (0xFFFFU<<16)/**< IN endpoint TxFIFO depth
|
||||||
|
mask. */
|
||||||
|
#define DIEPTXF_INEPTXFD(n) ((n)<<16) /**< IN endpoint TxFIFO depth
|
||||||
|
value. */
|
||||||
|
#define DIEPTXF_INEPTXSA_MASK (0xFFFF<<0) /**< IN endpoint FIFOx transmit
|
||||||
|
RAM start address mask. */
|
||||||
|
#define DIEPTXF_INEPTXSA(n) ((n)<<0) /**< IN endpoint FIFOx transmit
|
||||||
|
RAM start address value. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name GCCFG register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define GCCFG_NOVBUSSENS (1U<<21) /**< VBUS sensing disable. */
|
||||||
|
#define GCCFG_SOFOUTEN (1U<<20) /**< SOF output enable. */
|
||||||
|
#define GCCFG_VBUSBSEN (1U<<19) /**< Enable the VBUS sensing "B"
|
||||||
|
device. */
|
||||||
|
#define GCCFG_VBUSASEN (1U<<18) /**< Enable the VBUS sensing "A"
|
||||||
|
device. */
|
||||||
|
#define GCCFG_PWRDWN (1U<<16) /**< Power down. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name HPTXFSIZ register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define HPTXFSIZ_PTXFD_MASK (0xFFFFU<<16)/**< Host periodic TxFIFO
|
||||||
|
depth mask. */
|
||||||
|
#define HPTXFSIZ_PTXFD(n) ((n)<<16) /**< Host periodic TxFIFO
|
||||||
|
depth value. */
|
||||||
|
#define HPTXFSIZ_PTXSA_MASK (0xFFFFU<<0)/**< Host periodic TxFIFO
|
||||||
|
Start address mask. */
|
||||||
|
#define HPTXFSIZ_PTXSA(n) ((n)<<0) /**< Host periodic TxFIFO
|
||||||
|
start address value. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name HCFG register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define HCFG_FSLSS (1U<<2) /**< FS- and LS-only support. */
|
||||||
|
#define HCFG_FSLSPCS_MASK (3U<<0) /**< FS/LS PHY clock select
|
||||||
|
mask. */
|
||||||
|
#define HCFG_FSLSPCS_48 (1U<<0) /**< PHY clock is running at
|
||||||
|
48 MHz. */
|
||||||
|
#define HCFG_FSLSPCS_6 (2U<<0) /**< PHY clock is running at
|
||||||
|
6 MHz. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name HFIR register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define HFIR_FRIVL_MASK (0xFFFFU<<0)/**< Frame interval mask. */
|
||||||
|
#define HFIR_FRIVL(n) ((n)<<0) /**< Frame interval value. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name HFNUM register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define HFNUM_FTREM_MASK (0xFFFFU<<16)/**< Frame time Remaining mask.*/
|
||||||
|
#define HFNUM_FTREM(n) ((n)<<16) /**< Frame time Remaining value.*/
|
||||||
|
#define HFNUM_FRNUM_MASK (0xFFFFU<<0)/**< Frame number mask. */
|
||||||
|
#define HFNUM_FRNUM(n) ((n)<<0) /**< Frame number value. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name HPTXSTS register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define HPTXSTS_PTXQTOP_MASK (0xFFU<<24) /**< Top of the periodic
|
||||||
|
transmit request queue
|
||||||
|
mask. */
|
||||||
|
#define HPTXSTS_PTXQTOP(n) ((n)<<24) /**< Top of the periodic
|
||||||
|
transmit request queue
|
||||||
|
value. */
|
||||||
|
#define HPTXSTS_PTXQSAV_MASK (0xFF<<16) /**< Periodic transmit request
|
||||||
|
queue Space Available
|
||||||
|
mask. */
|
||||||
|
#define HPTXSTS_PTXQSAV(n) ((n)<<16) /**< Periodic transmit request
|
||||||
|
queue Space Available
|
||||||
|
value. */
|
||||||
|
#define HPTXSTS_PTXFSAVL_MASK (0xFFFF<<0) /**< Periodic transmit Data
|
||||||
|
FIFO Space Available
|
||||||
|
mask. */
|
||||||
|
#define HPTXSTS_PTXFSAVL(n) ((n)<<0) /**< Periodic transmit Data
|
||||||
|
FIFO Space Available
|
||||||
|
value. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name HAINT register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define HAINT_HAINT_MASK (0xFFFFU<<0)/**< Channel interrupts mask. */
|
||||||
|
#define HAINT_HAINT(n) ((n)<<0) /**< Channel interrupts value. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name HAINTMSK register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define HAINTMSK_HAINTM_MASK (0xFFFFU<<0)/**< Channel interrupt mask
|
||||||
|
mask. */
|
||||||
|
#define HAINTMSK_HAINTM(n) ((n)<<0) /**< Channel interrupt mask
|
||||||
|
value. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name HPRT register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define HPRT_PSPD_MASK (3U<<17) /**< Port speed mask. */
|
||||||
|
#define HPRT_PSPD_FS (1U<<17) /**< Full speed value. */
|
||||||
|
#define HPRT_PSPD_LS (2U<<17) /**< Low speed value. */
|
||||||
|
#define HPRT_PTCTL_MASK (15<<13) /**< Port Test control mask. */
|
||||||
|
#define HPRT_PTCTL(n) ((n)<<13) /**< Port Test control value. */
|
||||||
|
#define HPRT_PPWR (1U<<12) /**< Port power. */
|
||||||
|
#define HPRT_PLSTS_MASK (3U<<11) /**< Port Line status mask. */
|
||||||
|
#define HPRT_PLSTS_DM (1U<<11) /**< Logic level of D-. */
|
||||||
|
#define HPRT_PLSTS_DP (1U<<10) /**< Logic level of D+. */
|
||||||
|
#define HPRT_PRST (1U<<8) /**< Port reset. */
|
||||||
|
#define HPRT_PSUSP (1U<<7) /**< Port suspend. */
|
||||||
|
#define HPRT_PRES (1U<<6) /**< Port Resume. */
|
||||||
|
#define HPRT_POCCHNG (1U<<5) /**< Port overcurrent change. */
|
||||||
|
#define HPRT_POCA (1U<<4) /**< Port overcurrent active. */
|
||||||
|
#define HPRT_PENCHNG (1U<<3) /**< Port enable/disable change.*/
|
||||||
|
#define HPRT_PENA (1U<<2) /**< Port enable. */
|
||||||
|
#define HPRT_PCDET (1U<<1) /**< Port Connect detected. */
|
||||||
|
#define HPRT_PCSTS (1U<<0) /**< Port connect status. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name HCCHAR register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define HCCHAR_CHENA (1U<<31) /**< Channel enable. */
|
||||||
|
#define HCCHAR_CHDIS (1U<<30) /**< Channel Disable. */
|
||||||
|
#define HCCHAR_ODDFRM (1U<<29) /**< Odd frame. */
|
||||||
|
#define HCCHAR_DAD_MASK (0x7FU<<22) /**< Device Address mask. */
|
||||||
|
#define HCCHAR_DAD(n) ((n)<<22) /**< Device Address value. */
|
||||||
|
#define HCCHAR_MCNT_MASK (3U<<20) /**< Multicount mask. */
|
||||||
|
#define HCCHAR_MCNT(n) ((n)<<20) /**< Multicount value. */
|
||||||
|
#define HCCHAR_EPTYP_MASK (3U<<18) /**< Endpoint type mask. */
|
||||||
|
#define HCCHAR_EPTYP(n) ((n)<<18) /**< Endpoint type value. */
|
||||||
|
#define HCCHAR_EPTYP_CTL (0U<<18) /**< Control endpoint value. */
|
||||||
|
#define HCCHAR_EPTYP_ISO (1U<<18) /**< Isochronous endpoint value.*/
|
||||||
|
#define HCCHAR_EPTYP_BULK (2U<<18) /**< Bulk endpoint value. */
|
||||||
|
#define HCCHAR_EPTYP_INTR (3U<<18) /**< Interrupt endpoint value. */
|
||||||
|
#define HCCHAR_LSDEV (1U<<17) /**< Low-Speed device. */
|
||||||
|
#define HCCHAR_EPDIR (1U<<15) /**< Endpoint direction. */
|
||||||
|
#define HCCHAR_EPNUM_MASK (15U<<11) /**< Endpoint number mask. */
|
||||||
|
#define HCCHAR_EPNUM(n) ((n)<<11) /**< Endpoint number value. */
|
||||||
|
#define HCCHAR_MPS_MASK (0x7FFU<<0) /**< Maximum packet size mask. */
|
||||||
|
#define HCCHAR_MPS(n) ((n)<<0) /**< Maximum packet size value. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name HCINT register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define HCINT_DTERR (1U<<10) /**< Data toggle error. */
|
||||||
|
#define HCINT_FRMOR (1U<<9) /**< Frame overrun. */
|
||||||
|
#define HCINT_BBERR (1U<<8) /**< Babble error. */
|
||||||
|
#define HCINT_TRERR (1U<<7) /**< Transaction Error. */
|
||||||
|
#define HCINT_ACK (1U<<5) /**< ACK response
|
||||||
|
received/transmitted
|
||||||
|
interrupt. */
|
||||||
|
#define HCINT_NAK (1U<<4) /**< NAK response received
|
||||||
|
interrupt. */
|
||||||
|
#define HCINT_STALL (1U<<3) /**< STALL response received
|
||||||
|
interrupt. */
|
||||||
|
#define HCINT_CHH (1U<<1) /**< Channel halted. */
|
||||||
|
#define HCINT_XFRC (1U<<0) /**< Transfer completed. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name HCINTMSK register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define HCINTMSK_DTERRM (1U<<10) /**< Data toggle error mask. */
|
||||||
|
#define HCINTMSK_FRMORM (1U<<9) /**< Frame overrun mask. */
|
||||||
|
#define HCINTMSK_BBERRM (1U<<8) /**< Babble error mask. */
|
||||||
|
#define HCINTMSK_TRERRM (1U<<7) /**< Transaction error mask. */
|
||||||
|
#define HCINTMSK_NYET (1U<<6) /**< NYET response received
|
||||||
|
interrupt mask. */
|
||||||
|
#define HCINTMSK_ACKM (1U<<5) /**< ACK Response
|
||||||
|
received/transmitted
|
||||||
|
interrupt mask. */
|
||||||
|
#define HCINTMSK_NAKM (1U<<4) /**< NAK response received
|
||||||
|
interrupt mask. */
|
||||||
|
#define HCINTMSK_STALLM (1U<<3) /**< STALL response received
|
||||||
|
interrupt mask. */
|
||||||
|
#define HCINTMSK_AHBERRM (1U<<2)
|
||||||
|
#define HCINTMSK_CHHM (1U<<1) /**< Channel halted mask. */
|
||||||
|
#define HCINTMSK_XFRCM (1U<<0) /**< Transfer completed mask. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name HCTSIZ register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define HCTSIZ_DPID_MASK (3U<<29) /**< PID mask. */
|
||||||
|
#define HCTSIZ_DPID_DATA0 (0U<<29) /**< DATA0. */
|
||||||
|
#define HCTSIZ_DPID_DATA2 (1U<<29) /**< DATA2. */
|
||||||
|
#define HCTSIZ_DPID_DATA1 (2U<<29) /**< DATA1. */
|
||||||
|
#define HCTSIZ_DPID_MDATA (3U<<29) /**< MDATA. */
|
||||||
|
#define HCTSIZ_DPID_SETUP (3U<<29) /**< SETUP. */
|
||||||
|
#define HCTSIZ_PKTCNT_MASK (0x3FFU<<19)/**< Packet count mask. */
|
||||||
|
#define HCTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */
|
||||||
|
#define HCTSIZ_XFRSIZ_MASK (0x7FFFF<<0)/**< Transfer size mask. */
|
||||||
|
#define HCTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name DCFG register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define DCFG_PFIVL_MASK (3U<<11) /**< Periodic frame interval
|
||||||
|
mask. */
|
||||||
|
#define DCFG_PFIVL(n) ((n)<<11) /**< Periodic frame interval
|
||||||
|
value. */
|
||||||
|
#define DCFG_DAD_MASK (0x7FU<<4) /**< Device address mask. */
|
||||||
|
#define DCFG_DAD(n) ((n)<<4) /**< Device address value. */
|
||||||
|
#define DCFG_NZLSOHSK (1U<<2) /**< Non-Zero-Length status
|
||||||
|
OUT handshake. */
|
||||||
|
#define DCFG_DSPD_MASK (3U<<0) /**< Device speed mask. */
|
||||||
|
#define DCFG_DSPD_HS (0U<<0) /**< High speed (USB 2.0). */
|
||||||
|
#define DCFG_DSPD_HS_FS (1U<<0) /**< High speed (USB 2.0) in FS
|
||||||
|
mode. */
|
||||||
|
#define DCFG_DSPD_FS11 (3U<<0) /**< Full speed (USB 1.1
|
||||||
|
transceiver clock is 48
|
||||||
|
MHz). */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name DCTL register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define DCTL_POPRGDNE (1U<<11) /**< Power-on programming done. */
|
||||||
|
#define DCTL_CGONAK (1U<<10) /**< Clear global OUT NAK. */
|
||||||
|
#define DCTL_SGONAK (1U<<9) /**< Set global OUT NAK. */
|
||||||
|
#define DCTL_CGINAK (1U<<8) /**< Clear global non-periodic
|
||||||
|
IN NAK. */
|
||||||
|
#define DCTL_SGINAK (1U<<7) /**< Set global non-periodic
|
||||||
|
IN NAK. */
|
||||||
|
#define DCTL_TCTL_MASK (7U<<4) /**< Test control mask. */
|
||||||
|
#define DCTL_TCTL(n) ((n)<<4 /**< Test control value. */
|
||||||
|
#define DCTL_GONSTS (1U<<3) /**< Global OUT NAK status. */
|
||||||
|
#define DCTL_GINSTS (1U<<2) /**< Global non-periodic IN
|
||||||
|
NAK status. */
|
||||||
|
#define DCTL_SDIS (1U<<1) /**< Soft disconnect. */
|
||||||
|
#define DCTL_RWUSIG (1U<<0) /**< Remote wakeup signaling. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name DSTS register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define DSTS_FNSOF_MASK (0x3FFU<<8) /**< Frame number of the received
|
||||||
|
SOF mask. */
|
||||||
|
#define DSTS_FNSOF(n) ((n)<<8) /**< Frame number of the received
|
||||||
|
SOF value. */
|
||||||
|
#define DSTS_FNSOF_ODD (1U<<8) /**< Frame parity of the received
|
||||||
|
SOF value. */
|
||||||
|
#define DSTS_EERR (1U<<3) /**< Erratic error. */
|
||||||
|
#define DSTS_ENUMSPD_MASK (3U<<1) /**< Enumerated speed mask. */
|
||||||
|
#define DSTS_ENUMSPD_FS_48 (3U<<1) /**< Full speed (PHY clock is
|
||||||
|
running at 48 MHz). */
|
||||||
|
#define DSTS_ENUMSPD_HS_480 (0U<<1) /**< High speed. */
|
||||||
|
#define DSTS_SUSPSTS (1U<<0) /**< Suspend status. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name DIEPMSK register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define DIEPMSK_TXFEM (1U<<6) /**< Transmit FIFO empty mask. */
|
||||||
|
#define DIEPMSK_INEPNEM (1U<<6) /**< IN endpoint NAK effective
|
||||||
|
mask. */
|
||||||
|
#define DIEPMSK_ITTXFEMSK (1U<<4) /**< IN token received when
|
||||||
|
TxFIFO empty mask. */
|
||||||
|
#define DIEPMSK_TOCM (1U<<3) /**< Timeout condition mask. */
|
||||||
|
#define DIEPMSK_EPDM (1U<<1) /**< Endpoint disabled
|
||||||
|
interrupt mask. */
|
||||||
|
#define DIEPMSK_XFRCM (1U<<0) /**< Transfer completed
|
||||||
|
interrupt mask. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name DOEPMSK register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define DOEPMSK_OTEPDM (1U<<4) /**< OUT token received when
|
||||||
|
endpoint disabled mask. */
|
||||||
|
#define DOEPMSK_STUPM (1U<<3) /**< SETUP phase done mask. */
|
||||||
|
#define DOEPMSK_EPDM (1U<<1) /**< Endpoint disabled
|
||||||
|
interrupt mask. */
|
||||||
|
#define DOEPMSK_XFRCM (1U<<0) /**< Transfer completed
|
||||||
|
interrupt mask. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name DAINT register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define DAINT_OEPINT_MASK (0xFFFFU<<16)/**< OUT endpoint interrupt
|
||||||
|
bits mask. */
|
||||||
|
#define DAINT_OEPINT(n) ((n)<<16) /**< OUT endpoint interrupt
|
||||||
|
bits value. */
|
||||||
|
#define DAINT_IEPINT_MASK (0xFFFFU<<0)/**< IN endpoint interrupt
|
||||||
|
bits mask. */
|
||||||
|
#define DAINT_IEPINT(n) ((n)<<0) /**< IN endpoint interrupt
|
||||||
|
bits value. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name DAINTMSK register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define DAINTMSK_OEPM_MASK (0xFFFFU<<16)/**< OUT EP interrupt mask
|
||||||
|
bits mask. */
|
||||||
|
#define DAINTMSK_OEPM(n) (1U<<(16+(n)))/**< OUT EP interrupt mask
|
||||||
|
bits value. */
|
||||||
|
#define DAINTMSK_IEPM_MASK (0xFFFFU<<0)/**< IN EP interrupt mask
|
||||||
|
bits mask. */
|
||||||
|
#define DAINTMSK_IEPM(n) (1U<<(n)) /**< IN EP interrupt mask
|
||||||
|
bits value. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name DVBUSDIS register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define DVBUSDIS_VBUSDT_MASK (0xFFFFU<<0)/**< Device VBUS discharge
|
||||||
|
time mask. */
|
||||||
|
#define DVBUSDIS_VBUSDT(n) ((n)<<0) /**< Device VBUS discharge
|
||||||
|
time value. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name DVBUSPULSE register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define DVBUSPULSE_DVBUSP_MASK (0xFFFU<<0) /**< Device VBUSpulsing time
|
||||||
|
mask. */
|
||||||
|
#define DVBUSPULSE_DVBUSP(n) ((n)<<0) /**< Device VBUS pulsing time
|
||||||
|
value. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name DIEPEMPMSK register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define DIEPEMPMSK_INEPTXFEM(n) (1U<<(n)) /**< IN EP Tx FIFO empty
|
||||||
|
interrupt mask bit. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name DIEPCTL register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define DIEPCTL_EPENA (1U<<31) /**< Endpoint enable. */
|
||||||
|
#define DIEPCTL_EPDIS (1U<<30) /**< Endpoint disable. */
|
||||||
|
#define DIEPCTL_SD1PID (1U<<29) /**< Set DATA1 PID. */
|
||||||
|
#define DIEPCTL_SODDFRM (1U<<29) /**< Set odd frame. */
|
||||||
|
#define DIEPCTL_SD0PID (1U<<28) /**< Set DATA0 PID. */
|
||||||
|
#define DIEPCTL_SEVNFRM (1U<<28) /**< Set even frame. */
|
||||||
|
#define DIEPCTL_SNAK (1U<<27) /**< Set NAK. */
|
||||||
|
#define DIEPCTL_CNAK (1U<<26) /**< Clear NAK. */
|
||||||
|
#define DIEPCTL_TXFNUM_MASK (15U<<22) /**< TxFIFO number mask. */
|
||||||
|
#define DIEPCTL_TXFNUM(n) ((n)<<22) /**< TxFIFO number value. */
|
||||||
|
#define DIEPCTL_STALL (1U<<21) /**< STALL handshake. */
|
||||||
|
#define DIEPCTL_SNPM (1U<<20) /**< Snoop mode. */
|
||||||
|
#define DIEPCTL_EPTYP_MASK (3<<18) /**< Endpoint type mask. */
|
||||||
|
#define DIEPCTL_EPTYP_CTRL (0U<<18) /**< Control. */
|
||||||
|
#define DIEPCTL_EPTYP_ISO (1U<<18) /**< Isochronous. */
|
||||||
|
#define DIEPCTL_EPTYP_BULK (2U<<18) /**< Bulk. */
|
||||||
|
#define DIEPCTL_EPTYP_INTR (3U<<18) /**< Interrupt. */
|
||||||
|
#define DIEPCTL_NAKSTS (1U<<17) /**< NAK status. */
|
||||||
|
#define DIEPCTL_EONUM (1U<<16) /**< Even/odd frame. */
|
||||||
|
#define DIEPCTL_DPID (1U<<16) /**< Endpoint data PID. */
|
||||||
|
#define DIEPCTL_USBAEP (1U<<15) /**< USB active endpoint. */
|
||||||
|
#define DIEPCTL_MPSIZ_MASK (0x3FFU<<0) /**< Maximum Packet size mask. */
|
||||||
|
#define DIEPCTL_MPSIZ(n) ((n)<<0) /**< Maximum Packet size value. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name DIEPINT register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define DIEPINT_TXFE (1U<<7) /**< Transmit FIFO empty. */
|
||||||
|
#define DIEPINT_INEPNE (1U<<6) /**< IN endpoint NAK effective. */
|
||||||
|
#define DIEPINT_ITTXFE (1U<<4) /**< IN Token received when
|
||||||
|
TxFIFO is empty. */
|
||||||
|
#define DIEPINT_TOC (1U<<3) /**< Timeout condition. */
|
||||||
|
#define DIEPINT_EPDISD (1U<<1) /**< Endpoint disabled
|
||||||
|
interrupt. */
|
||||||
|
#define DIEPINT_XFRC (1U<<0) /**< Transfer completed. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name DIEPTSIZ register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define DIEPTSIZ_MCNT_MASK (3U<<29) /**< Multi count mask. */
|
||||||
|
#define DIEPTSIZ_MCNT(n) ((n)<<29) /**< Multi count value. */
|
||||||
|
#define DIEPTSIZ_PKTCNT_MASK (0x3FF<<19) /**< Packet count mask. */
|
||||||
|
#define DIEPTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */
|
||||||
|
#define DIEPTSIZ_XFRSIZ_MASK (0x7FFFFU<<0)/**< Transfer size mask. */
|
||||||
|
#define DIEPTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name DTXFSTS register bit definitions.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define DTXFSTS_INEPTFSAV_MASK (0xFFFF<<0) /**< IN endpoint TxFIFO space
|
||||||
|
available. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name DOEPCTL register bit definitions.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define DOEPCTL_EPENA (1U<<31) /**< Endpoint enable. */
|
||||||
|
#define DOEPCTL_EPDIS (1U<<30) /**< Endpoint disable. */
|
||||||
|
#define DOEPCTL_SD1PID (1U<<29) /**< Set DATA1 PID. */
|
||||||
|
#define DOEPCTL_SODDFRM (1U<<29) /**< Set odd frame. */
|
||||||
|
#define DOEPCTL_SD0PID (1U<<28) /**< Set DATA0 PID. */
|
||||||
|
#define DOEPCTL_SEVNFRM (1U<<28) /**< Set even frame. */
|
||||||
|
#define DOEPCTL_SNAK (1U<<27) /**< Set NAK. */
|
||||||
|
#define DOEPCTL_CNAK (1U<<26) /**< Clear NAK. */
|
||||||
|
#define DOEPCTL_STALL (1U<<21) /**< STALL handshake. */
|
||||||
|
#define DOEPCTL_SNPM (1U<<20) /**< Snoop mode. */
|
||||||
|
#define DOEPCTL_EPTYP_MASK (3U<<18) /**< Endpoint type mask. */
|
||||||
|
#define DOEPCTL_EPTYP_CTRL (0U<<18) /**< Control. */
|
||||||
|
#define DOEPCTL_EPTYP_ISO (1U<<18) /**< Isochronous. */
|
||||||
|
#define DOEPCTL_EPTYP_BULK (2U<<18) /**< Bulk. */
|
||||||
|
#define DOEPCTL_EPTYP_INTR (3U<<18) /**< Interrupt. */
|
||||||
|
#define DOEPCTL_NAKSTS (1U<<17) /**< NAK status. */
|
||||||
|
#define DOEPCTL_EONUM (1U<<16) /**< Even/odd frame. */
|
||||||
|
#define DOEPCTL_DPID (1U<<16) /**< Endpoint data PID. */
|
||||||
|
#define DOEPCTL_USBAEP (1U<<15) /**< USB active endpoint. */
|
||||||
|
#define DOEPCTL_MPSIZ_MASK (0x3FFU<<0) /**< Maximum Packet size mask. */
|
||||||
|
#define DOEPCTL_MPSIZ(n) ((n)<<0) /**< Maximum Packet size value. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name DOEPINT register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define DOEPINT_B2BSTUP (1U<<6) /**< Back-to-back SETUP packets
|
||||||
|
received. */
|
||||||
|
#define DOEPINT_OTEPDIS (1U<<4) /**< OUT token received when
|
||||||
|
endpoint disabled. */
|
||||||
|
#define DOEPINT_STUP (1U<<3) /**< SETUP phase done. */
|
||||||
|
#define DOEPINT_EPDISD (1U<<1) /**< Endpoint disabled
|
||||||
|
interrupt. */
|
||||||
|
#define DOEPINT_XFRC (1U<<0) /**< Transfer completed
|
||||||
|
interrupt. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name DOEPTSIZ register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define DOEPTSIZ_RXDPID_MASK (3U<<29) /**< Received data PID mask. */
|
||||||
|
#define DOEPTSIZ_RXDPID(n) ((n)<<29) /**< Received data PID value. */
|
||||||
|
#define DOEPTSIZ_STUPCNT_MASK (3U<<29) /**< SETUP packet count mask. */
|
||||||
|
#define DOEPTSIZ_STUPCNT(n) ((n)<<29) /**< SETUP packet count value. */
|
||||||
|
#define DOEPTSIZ_PKTCNT_MASK (0x3FFU<<19)/**< Packet count mask. */
|
||||||
|
#define DOEPTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */
|
||||||
|
#define DOEPTSIZ_XFRSIZ_MASK (0x7FFFFU<<0)/**< Transfer size mask. */
|
||||||
|
#define DOEPTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name PCGCCTL register bit definitions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define PCGCCTL_PHYSUSP (1U<<4) /**< PHY Suspended. */
|
||||||
|
#define PCGCCTL_GATEHCLK (1U<<1) /**< Gate HCLK. */
|
||||||
|
#define PCGCCTL_STPPCLK (1U<<0) /**< Stop PCLK. */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief OTG_FS registers block memory address.
|
||||||
|
*/
|
||||||
|
#define OTG_FS_ADDR 0x50000000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief OTG_HS registers block memory address.
|
||||||
|
*/
|
||||||
|
#define OTG_HS_ADDR 0x40040000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Accesses to the OTG_FS registers block.
|
||||||
|
*/
|
||||||
|
#define OTG_FS ((stm32_otg_t *)OTG_FS_ADDR)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Accesses to the OTG_HS registers block.
|
||||||
|
*/
|
||||||
|
#define OTG_HS ((stm32_otg_t *)OTG_HS_ADDR)
|
||||||
|
|
||||||
|
#endif /* _STM32_OTG_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,153 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||||
|
Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef USBH_LLD_H_
|
||||||
|
#define USBH_LLD_H_
|
||||||
|
|
||||||
|
#include "hal.h"
|
||||||
|
|
||||||
|
#if HAL_USE_USBH
|
||||||
|
|
||||||
|
#include "osal.h"
|
||||||
|
#include "stm32_otg.h"
|
||||||
|
|
||||||
|
/* TODO:
|
||||||
|
*
|
||||||
|
* - Implement ISO/INT OUT and test
|
||||||
|
* - Consider DMA mode for OTG_HS, consider external PHY for HS.
|
||||||
|
* - Implement a data pump thread, so we don't have to copy data from the ISR
|
||||||
|
* This might be a bad idea for small endpoint packet sizes (the context switch
|
||||||
|
* could be longer than the copy)
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
USBH_LLD_CTRLPHASE_SETUP,
|
||||||
|
USBH_LLD_CTRLPHASE_DATA,
|
||||||
|
USBH_LLD_CTRLPHASE_STATUS
|
||||||
|
} usbh_lld_ctrlphase_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
USBH_LLD_HALTREASON_NONE,
|
||||||
|
USBH_LLD_HALTREASON_XFRC,
|
||||||
|
USBH_LLD_HALTREASON_NAK,
|
||||||
|
USBH_LLD_HALTREASON_STALL,
|
||||||
|
USBH_LLD_HALTREASON_ERROR,
|
||||||
|
USBH_LLD_HALTREASON_ABORT
|
||||||
|
} usbh_lld_halt_reason_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct stm32_hc_management {
|
||||||
|
struct list_head node;
|
||||||
|
|
||||||
|
stm32_otg_host_chn_t *hc;
|
||||||
|
volatile uint32_t *fifo;
|
||||||
|
usbh_ep_t *ep;
|
||||||
|
uint16_t haintmsk;
|
||||||
|
usbh_lld_halt_reason_t halt_reason;
|
||||||
|
} stm32_hc_management_t;
|
||||||
|
|
||||||
|
|
||||||
|
#define _usbhdriver_ll_data \
|
||||||
|
stm32_otg_t *otg; \
|
||||||
|
/* channels */ \
|
||||||
|
uint8_t channels_number; \
|
||||||
|
stm32_hc_management_t channels[STM32_OTG2_CHANNELS_NUMBER]; \
|
||||||
|
struct list_head ch_free[2]; \
|
||||||
|
/* Enpoints being processed */ \
|
||||||
|
struct list_head ep_active_lists[4]; \
|
||||||
|
/* Pending endpoints */ \
|
||||||
|
struct list_head ep_pending_lists[4];
|
||||||
|
|
||||||
|
|
||||||
|
#define _usbh_ep_ll_data \
|
||||||
|
struct list_head *active_list; /* shortcut to ep list */ \
|
||||||
|
struct list_head *pending_list; /* shortcut to ep list */ \
|
||||||
|
struct list_head urb_list; /* list of URBs queued in this EP */ \
|
||||||
|
struct list_head node; /* this EP */ \
|
||||||
|
uint32_t hcintmsk; \
|
||||||
|
uint32_t hcchar; \
|
||||||
|
uint32_t dt_mask; /* data-toggle mask */ \
|
||||||
|
/* current transfer */ \
|
||||||
|
struct { \
|
||||||
|
stm32_hc_management_t *hcm; /* assigned channel */ \
|
||||||
|
uint32_t len; /* this transfer's total length */ \
|
||||||
|
uint8_t *buf; /* this transfer's buffer */ \
|
||||||
|
uint32_t partial; /* this transfer's partial length */\
|
||||||
|
uint16_t packets; /* packets allocated */ \
|
||||||
|
union { \
|
||||||
|
uint32_t frame_counter; /* frame counter (for INT) */ \
|
||||||
|
usbh_lld_ctrlphase_t ctrl_phase; /* control phase (for CTRL) */ \
|
||||||
|
} u; \
|
||||||
|
uint8_t error_count; /* error count */ \
|
||||||
|
} xfer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define _usbh_port_ll_data \
|
||||||
|
uint16_t lld_c_status; \
|
||||||
|
uint16_t lld_status;
|
||||||
|
|
||||||
|
#define _usbh_device_ll_data
|
||||||
|
|
||||||
|
#define _usbh_hub_ll_data
|
||||||
|
|
||||||
|
#define _usbh_urb_ll_data \
|
||||||
|
struct list_head node; \
|
||||||
|
bool queued;
|
||||||
|
|
||||||
|
|
||||||
|
#define usbh_lld_urb_object_init(urb) \
|
||||||
|
do { \
|
||||||
|
osalDbgAssert(((uint32_t)urb->buff & 3) == 0, \
|
||||||
|
"use USBH_DEFINE_BUFFER() to declare the IO buffers"); \
|
||||||
|
urb->queued = FALSE; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
#define usbh_lld_urb_object_reset(urb) \
|
||||||
|
do { \
|
||||||
|
osalDbgAssert(urb->queued == FALSE, "wrong state"); \
|
||||||
|
osalDbgAssert(((uint32_t)urb->buff & 3) == 0, \
|
||||||
|
"use USBH_DEFINE_BUFFER() to declare the IO buffers"); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void usbh_lld_init(void);
|
||||||
|
void usbh_lld_start(USBHDriver *usbh);
|
||||||
|
void usbh_lld_ep_object_init(usbh_ep_t *ep);
|
||||||
|
void usbh_lld_ep_open(usbh_ep_t *ep);
|
||||||
|
void usbh_lld_ep_close(usbh_ep_t *ep);
|
||||||
|
void usbh_lld_urb_submit(usbh_urb_t *urb);
|
||||||
|
bool usbh_lld_urb_abort(usbh_urb_t *urb, usbh_urbstatus_t status);
|
||||||
|
usbh_urbstatus_t usbh_lld_root_hub_request(USBHDriver *usbh, uint8_t bmRequestType, uint8_t bRequest,
|
||||||
|
uint16_t wvalue, uint16_t windex, uint16_t wlength, uint8_t *buf);
|
||||||
|
uint8_t usbh_lld_roothub_get_statuschange_bitmap(USBHDriver *usbh);
|
||||||
|
|
||||||
|
#define usbh_lld_epreset(ep) do {(ep)->dt_mask = HCTSIZ_DPID_DATA0;} while (0);
|
||||||
|
|
||||||
|
#ifdef __IAR_SYSTEMS_ICC__
|
||||||
|
#define USBH_LLD_DEFINE_BUFFER(type, name) type name
|
||||||
|
#else
|
||||||
|
#define USBH_LLD_DEFINE_BUFFER(type, name) type name __attribute__((aligned(4)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* USBH_LLD_H_ */
|
|
@ -6,10 +6,12 @@ PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/DMA2Dv1/stm32_dma2d.c \
|
||||||
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sram.c \
|
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sram.c \
|
||||||
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/LTDCv1/stm32_ltdc.c \
|
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/LTDCv1/stm32_ltdc.c \
|
||||||
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/eicu_lld.c \
|
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/eicu_lld.c \
|
||||||
|
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/USBHv1/usbh_lld.c \
|
||||||
${CHIBIOS_CONTRIB}/os/hal/src/fsmc_sdram.c
|
${CHIBIOS_CONTRIB}/os/hal/src/fsmc_sdram.c
|
||||||
|
|
||||||
PLATFORMINC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/DMA2Dv1 \
|
PLATFORMINC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/DMA2Dv1 \
|
||||||
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/FSMCv1 \
|
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/FSMCv1 \
|
||||||
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/LTDCv1 \
|
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/LTDCv1 \
|
||||||
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1 \
|
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1 \
|
||||||
|
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/USBHv1 \
|
||||||
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD
|
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD
|
||||||
|
|
|
@ -64,6 +64,10 @@ void halCommunityInit(void) {
|
||||||
#if HAL_USE_CRC || defined(__DOXYGEN__)
|
#if HAL_USE_CRC || defined(__DOXYGEN__)
|
||||||
crcInit();
|
crcInit();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if HAL_USE_USBH || defined(__DOXYGEN__)
|
||||||
|
usbhInit();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* HAL_USE_COMMUNITY */
|
#endif /* HAL_USE_COMMUNITY */
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,536 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||||
|
Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hal.h"
|
||||||
|
|
||||||
|
#if HAL_USE_USBH
|
||||||
|
|
||||||
|
#include "ch.h"
|
||||||
|
#include "usbh/debug.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include "chprintf.h"
|
||||||
|
|
||||||
|
#if USBH_DEBUG_ENABLE
|
||||||
|
|
||||||
|
#define MAX_FILLER 11
|
||||||
|
#define FLOAT_PRECISION 9
|
||||||
|
#define MPRINTF_USE_FLOAT 0
|
||||||
|
|
||||||
|
static char *long_to_string_with_divisor(char *p, long num, unsigned radix, long divisor)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *q;
|
||||||
|
long l, ll;
|
||||||
|
|
||||||
|
l = num;
|
||||||
|
if (divisor == 0) {
|
||||||
|
ll = num;
|
||||||
|
} else {
|
||||||
|
ll = divisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
q = p + MAX_FILLER;
|
||||||
|
do {
|
||||||
|
i = (int)(l % radix);
|
||||||
|
i += '0';
|
||||||
|
if (i > '9') {
|
||||||
|
i += 'A' - '0' - 10;
|
||||||
|
}
|
||||||
|
*--q = i;
|
||||||
|
l /= radix;
|
||||||
|
} while ((ll /= radix) != 0);
|
||||||
|
|
||||||
|
i = (int)(p + MAX_FILLER - q);
|
||||||
|
do {
|
||||||
|
*p++ = *q++;
|
||||||
|
} while (--i);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *ltoa(char *p, long num, unsigned radix) {
|
||||||
|
|
||||||
|
return long_to_string_with_divisor(p, num, radix, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MPRINTF_USE_FLOAT
|
||||||
|
static const long _pow10[FLOAT_PRECISION] = {10, 100, 1000, 10000, 100000, 1000000,
|
||||||
|
10000000, 100000000, 1000000000};
|
||||||
|
static const double m10[FLOAT_PRECISION] = {5.0/100, 5.0/1000, 5.0/10000, 5.0/100000, 5.0/1000000,
|
||||||
|
5.0/10000000, 5.0/100000000, 5.0/1000000000, 5.0/10000000000};
|
||||||
|
|
||||||
|
static char *ftoa(char *p, double num, unsigned long precision, bool dot) {
|
||||||
|
long l;
|
||||||
|
char *q;
|
||||||
|
double r;
|
||||||
|
|
||||||
|
|
||||||
|
if (precision == 0) {
|
||||||
|
l = (long)(num + 0.5);
|
||||||
|
return long_to_string_with_divisor(p, l, 10, 0);
|
||||||
|
} else {
|
||||||
|
if (precision > FLOAT_PRECISION) precision = FLOAT_PRECISION;
|
||||||
|
r = m10[precision - 1];
|
||||||
|
precision = _pow10[precision - 1];
|
||||||
|
|
||||||
|
l = (long)num;
|
||||||
|
p = long_to_string_with_divisor(p, l, 10, 0);
|
||||||
|
if (dot) *p++ = '.';
|
||||||
|
l = (long)((num - l + r) * precision);
|
||||||
|
q = long_to_string_with_divisor(p, l, 10, precision / 10) - 1;
|
||||||
|
|
||||||
|
while (q > p) {
|
||||||
|
if (*q != '0') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
--q;
|
||||||
|
}
|
||||||
|
return ++q;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void _put(char c) {
|
||||||
|
input_queue_t *iqp = &USBH_DEBUG_USBHD.iq;
|
||||||
|
|
||||||
|
if (chIQIsFullI(iqp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
iqp->q_counter++;
|
||||||
|
*iqp->q_wrptr++ = c;
|
||||||
|
if (iqp->q_wrptr >= iqp->q_top)
|
||||||
|
iqp->q_wrptr = iqp->q_buffer;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int _dbg_printf(const char *fmt, va_list ap) {
|
||||||
|
char *p, *s, c, filler;
|
||||||
|
int i, precision, width;
|
||||||
|
int n = 0;
|
||||||
|
bool is_long, left_align, sign;
|
||||||
|
long l;
|
||||||
|
#if MPRINTF_USE_FLOAT
|
||||||
|
double f;
|
||||||
|
char tmpbuf[2*MAX_FILLER + 1];
|
||||||
|
#else
|
||||||
|
char tmpbuf[MAX_FILLER + 1];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
|
||||||
|
//agarrar nuevo caracter de formato
|
||||||
|
c = *fmt++;
|
||||||
|
|
||||||
|
//chequeo eos
|
||||||
|
if (c == 0) return n;
|
||||||
|
|
||||||
|
//copio los caracteres comunes
|
||||||
|
if (c != '%') {
|
||||||
|
_put(c);
|
||||||
|
n++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//encontré un '%'
|
||||||
|
p = tmpbuf;
|
||||||
|
s = tmpbuf;
|
||||||
|
|
||||||
|
//left align
|
||||||
|
left_align = FALSE;
|
||||||
|
if (*fmt == '-') {
|
||||||
|
fmt++;
|
||||||
|
left_align = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
sign = FALSE;
|
||||||
|
if (*fmt == '+') {
|
||||||
|
fmt++;
|
||||||
|
sign = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//filler
|
||||||
|
filler = ' ';
|
||||||
|
if (*fmt == '0') {
|
||||||
|
fmt++;
|
||||||
|
filler = '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
//width
|
||||||
|
width = 0;
|
||||||
|
while (TRUE) {
|
||||||
|
c = *fmt++;
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
c -= '0';
|
||||||
|
else if (c == '*')
|
||||||
|
c = va_arg(ap, int);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
width = width * 10 + c;
|
||||||
|
}
|
||||||
|
|
||||||
|
//precision
|
||||||
|
precision = 0;
|
||||||
|
if (c == '.') {
|
||||||
|
|
||||||
|
if (*fmt == 'n') {
|
||||||
|
fmt++;
|
||||||
|
|
||||||
|
}
|
||||||
|
while (TRUE) {
|
||||||
|
c = *fmt++;
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
c -= '0';
|
||||||
|
else if (c == '*')
|
||||||
|
c = va_arg(ap, int);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
precision = precision * 10 + c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//long modifier
|
||||||
|
if (c == 'l' || c == 'L') {
|
||||||
|
is_long = TRUE;
|
||||||
|
if (*fmt)
|
||||||
|
c = *fmt++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
is_long = (c >= 'A') && (c <= 'Z');
|
||||||
|
|
||||||
|
/* Command decoding.*/
|
||||||
|
switch (c) {
|
||||||
|
//char
|
||||||
|
case 'c':
|
||||||
|
filler = ' ';
|
||||||
|
*p++ = va_arg(ap, int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//string
|
||||||
|
case 's':
|
||||||
|
filler = ' ';
|
||||||
|
if ((s = va_arg(ap, char *)) == 0)
|
||||||
|
s = (char *)"(null)";
|
||||||
|
if (precision == 0)
|
||||||
|
precision = 32767;
|
||||||
|
|
||||||
|
//strlen con límite hasta precision
|
||||||
|
for (p = s; *p && (--precision >= 0); p++)
|
||||||
|
;
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
case 'D':
|
||||||
|
case 'd':
|
||||||
|
case 'I':
|
||||||
|
case 'i':
|
||||||
|
if (is_long)
|
||||||
|
l = va_arg(ap, long);
|
||||||
|
else
|
||||||
|
l = va_arg(ap, int);
|
||||||
|
if (l < 0) {
|
||||||
|
*p++ = '-';
|
||||||
|
l = -l;
|
||||||
|
sign = TRUE;
|
||||||
|
} else if (sign) {
|
||||||
|
*p++ = '+';
|
||||||
|
}
|
||||||
|
p = ltoa(p, l, 10);
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if MPRINTF_USE_FLOAT
|
||||||
|
case 'f':
|
||||||
|
f = va_arg(ap, double);
|
||||||
|
if (f < 0) {
|
||||||
|
*p++ = '-';
|
||||||
|
f = -f;
|
||||||
|
sign = TRUE;
|
||||||
|
} else if (sign) {
|
||||||
|
*p++ = '+';
|
||||||
|
}
|
||||||
|
if (prec == FALSE) precision = 6;
|
||||||
|
p = ftoa(p, f, precision, dot);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
case 'X':
|
||||||
|
case 'x':
|
||||||
|
c = 16;
|
||||||
|
goto unsigned_common;
|
||||||
|
case 'U':
|
||||||
|
case 'u':
|
||||||
|
c = 10;
|
||||||
|
goto unsigned_common;
|
||||||
|
case 'O':
|
||||||
|
case 'o':
|
||||||
|
c = 8;
|
||||||
|
|
||||||
|
unsigned_common:
|
||||||
|
if (is_long)
|
||||||
|
l = va_arg(ap, unsigned long);
|
||||||
|
else
|
||||||
|
l = va_arg(ap, unsigned int);
|
||||||
|
p = ltoa(p, l, c);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//copiar
|
||||||
|
default:
|
||||||
|
*p++ = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//longitud
|
||||||
|
i = (int)(p - s);
|
||||||
|
|
||||||
|
//calculo cuántos caracteres de filler debo poner
|
||||||
|
if ((width -= i) < 0)
|
||||||
|
width = 0;
|
||||||
|
|
||||||
|
if (left_align == FALSE)
|
||||||
|
width = -width;
|
||||||
|
|
||||||
|
if (width < 0) {
|
||||||
|
//alineado a la derecha
|
||||||
|
|
||||||
|
//poner el signo adelante
|
||||||
|
if (sign && filler == '0') {
|
||||||
|
_put(*s++);
|
||||||
|
n++;
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
|
||||||
|
//fill a la izquierda
|
||||||
|
do {
|
||||||
|
_put(filler);
|
||||||
|
n++;
|
||||||
|
} while (++width != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//copiar los caracteres
|
||||||
|
while (--i >= 0) {
|
||||||
|
_put(*s++);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//fill a la derecha
|
||||||
|
while (width) {
|
||||||
|
_put(filler);
|
||||||
|
n++;
|
||||||
|
width--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//return n; // can raise 'code is unreachable' warning
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _print_hdr(void)
|
||||||
|
{
|
||||||
|
uint32_t hfnum = USBH_DEBUG_USBHD.otg->HFNUM;
|
||||||
|
uint16_t hfir = USBH_DEBUG_USBHD.otg->HFIR;
|
||||||
|
|
||||||
|
_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
chSysRestoreStatusX(sts);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
iqp->q_counter = sizeof(USBH_DEBUG_USBHD.dbg_buff) - rem;
|
||||||
|
chThdDequeueNextI(&USBH_DEBUG_USBHD.iq.q_waiting, Q_OK);
|
||||||
|
chSysRestoreStatusX(sts);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usbDbgReset(void) {
|
||||||
|
const char *msg = "\r\n\r\n==== DEBUG OUTPUT RESET ====\r\n";
|
||||||
|
|
||||||
|
syssts_t sts = chSysGetStatusAndLockX();
|
||||||
|
chIQResetI(&USBH_DEBUG_USBHD.iq);
|
||||||
|
chOQResetI(&USBH_DEBUG_SD.oqueue);
|
||||||
|
while (*msg) {
|
||||||
|
*USBH_DEBUG_SD.oqueue.q_wrptr++ = *msg++;
|
||||||
|
USBH_DEBUG_SD.oqueue.q_counter--;
|
||||||
|
}
|
||||||
|
chSysRestoreStatusX(sts);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _get(void) {
|
||||||
|
if (!USBH_DEBUG_USBHD.iq.q_counter) return -1;
|
||||||
|
USBH_DEBUG_USBHD.iq.q_counter--;
|
||||||
|
uint8_t b = *USBH_DEBUG_USBHD.iq.q_rdptr++;
|
||||||
|
if (USBH_DEBUG_USBHD.iq.q_rdptr >= USBH_DEBUG_USBHD.iq.q_top) {
|
||||||
|
USBH_DEBUG_USBHD.iq.q_rdptr = USBH_DEBUG_USBHD.iq.q_buffer;
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usbDbgSystemHalted(void) {
|
||||||
|
while (true) {
|
||||||
|
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++;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int c;
|
||||||
|
int state = 0;
|
||||||
|
for (;;) {
|
||||||
|
c = _get(); if (c < 0) break;
|
||||||
|
|
||||||
|
if (state == 0) {
|
||||||
|
if (c == 0xff) state = 1;
|
||||||
|
} else if (state == 1) {
|
||||||
|
if (c == 0xff) state = 2;
|
||||||
|
else (state = 0);
|
||||||
|
} else {
|
||||||
|
c = _get(); if (c < 0) return;
|
||||||
|
c = _get(); if (c < 0) return;
|
||||||
|
c = _get(); if (c < 0) return;
|
||||||
|
c = _get(); if (c < 0) return;
|
||||||
|
c = _get(); if (c < 0) return;
|
||||||
|
|
||||||
|
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';
|
||||||
|
state = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (!(USART1->SR & USART_SR_TXE));
|
||||||
|
USART1->DR = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_debug_thread(void *p) {
|
||||||
|
USBHDriver *host = (USBHDriver *)p;
|
||||||
|
uint8_t state = 0;
|
||||||
|
|
||||||
|
chRegSetThreadName("USBH_DBG");
|
||||||
|
while (true) {
|
||||||
|
msg_t c = chIQGet(&host->iq);
|
||||||
|
if (c < 0) goto reset;
|
||||||
|
|
||||||
|
if (state == 0) {
|
||||||
|
if (c == 0xff) state = 1;
|
||||||
|
} else if (state == 1) {
|
||||||
|
if (c == 0xff) state = 2;
|
||||||
|
else (state = 0);
|
||||||
|
} else {
|
||||||
|
uint16_t hfir;
|
||||||
|
uint32_t hfnum;
|
||||||
|
|
||||||
|
hfir = c;
|
||||||
|
c = chIQGet(&host->iq); if (c < 0) goto reset;
|
||||||
|
hfir |= c << 8;
|
||||||
|
|
||||||
|
c = chIQGet(&host->iq); if (c < 0) goto reset;
|
||||||
|
hfnum = c;
|
||||||
|
c = chIQGet(&host->iq); if (c < 0) goto reset;
|
||||||
|
hfnum |= c << 8;
|
||||||
|
c = chIQGet(&host->iq); if (c < 0) goto reset;
|
||||||
|
hfnum |= c << 16;
|
||||||
|
c = chIQGet(&host->iq); if (c < 0) goto reset;
|
||||||
|
hfnum |= c << 24;
|
||||||
|
|
||||||
|
uint32_t f = hfnum & 0xffff;
|
||||||
|
uint32_t p = 1000 - ((hfnum >> 16) / (hfir / 1000));
|
||||||
|
chprintf((BaseSequentialStream *)&USBH_DEBUG_SD, "%05d.%03d ", f, p);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
c = chIQGet(&host->iq); if (c < 0) goto reset;
|
||||||
|
if (!c) {
|
||||||
|
sdPut(&USBH_DEBUG_SD, '\r');
|
||||||
|
sdPut(&USBH_DEBUG_SD, '\n');
|
||||||
|
state = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sdPut(&USBH_DEBUG_SD, (uint8_t)c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
reset:
|
||||||
|
state = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void usbDbgInit(USBHDriver *host) {
|
||||||
|
if (host != &USBH_DEBUG_USBHD)
|
||||||
|
return;
|
||||||
|
chIQObjectInit(&USBH_DEBUG_USBHD.iq, USBH_DEBUG_USBHD.dbg_buff, sizeof(USBH_DEBUG_USBHD.dbg_buff), 0, 0);
|
||||||
|
chThdCreateStatic(USBH_DEBUG_USBHD.waDebug, sizeof(USBH_DEBUG_USBHD.waDebug), NORMALPRIO, usb_debug_thread, &USBH_DEBUG_USBHD);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,165 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||||
|
Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hal.h"
|
||||||
|
|
||||||
|
#if HAL_USE_USBH
|
||||||
|
|
||||||
|
#include "usbh/defs.h"
|
||||||
|
#include "usbh/desciter.h"
|
||||||
|
|
||||||
|
void cfg_iter_init(generic_iterator_t *icfg, const uint8_t *buff, uint16_t rem) {
|
||||||
|
icfg->valid = 0;
|
||||||
|
|
||||||
|
if ((buff[0] < 2) || (rem < 2) || (rem < buff[0])
|
||||||
|
|| (buff[0] < USBH_DT_CONFIG_SIZE)
|
||||||
|
|| (buff[1] != USBH_DT_CONFIG))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (rem > ((usbh_config_descriptor_t *)buff)->wTotalLength) {
|
||||||
|
rem = ((usbh_config_descriptor_t *)buff)->wTotalLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
icfg->valid = 1;
|
||||||
|
icfg->rem = rem;
|
||||||
|
icfg->curr = buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void if_iter_next(if_iterator_t *iif) {
|
||||||
|
const uint8_t *curr = iif->curr;
|
||||||
|
uint16_t rem = iif->rem;
|
||||||
|
|
||||||
|
iif->valid = 0;
|
||||||
|
|
||||||
|
if ((curr[0] < 2) || (rem < 2) || (rem < curr[0]))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
rem -= curr[0];
|
||||||
|
curr += curr[0];
|
||||||
|
|
||||||
|
if ((curr[0] < 2) || (rem < 2) || (rem < curr[0]))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (curr[1] == USBH_DT_INTERFACE_ASSOCIATION) {
|
||||||
|
if (curr[0] < USBH_DT_INTERFACE_ASSOCIATION_SIZE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
iif->iad = (usbh_ia_descriptor_t *)curr;
|
||||||
|
|
||||||
|
} else if (curr[1] == USBH_DT_INTERFACE) {
|
||||||
|
if (curr[0] < USBH_DT_INTERFACE_SIZE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (iif->iad) {
|
||||||
|
if ((curr[2] < iif->iad->bFirstInterface)
|
||||||
|
|| (curr[2] >= (iif->iad->bFirstInterface + iif->iad->bInterfaceCount)))
|
||||||
|
iif->iad = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iif->valid = 1;
|
||||||
|
iif->rem = rem;
|
||||||
|
iif->curr = curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void if_iter_init(if_iterator_t *iif, const generic_iterator_t *icfg) {
|
||||||
|
iif->iad = 0;
|
||||||
|
iif->curr = icfg->curr;
|
||||||
|
iif->rem = icfg->rem;
|
||||||
|
if_iter_next(iif);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ep_iter_next(generic_iterator_t *iep) {
|
||||||
|
const uint8_t *curr = iep->curr;
|
||||||
|
uint16_t rem = iep->rem;
|
||||||
|
|
||||||
|
iep->valid = 0;
|
||||||
|
|
||||||
|
if ((curr[0] < 2) || (rem < 2) || (rem < curr[0]))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
rem -= curr[0];
|
||||||
|
curr += curr[0];
|
||||||
|
|
||||||
|
if ((curr[0] < 2) || (rem < 2) || (rem < curr[0]))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((curr[1] == USBH_DT_INTERFACE_ASSOCIATION)
|
||||||
|
|| (curr[1] == USBH_DT_INTERFACE)
|
||||||
|
|| (curr[1] == USBH_DT_CONFIG)) {
|
||||||
|
return;
|
||||||
|
} else if (curr[1] == USBH_DT_ENDPOINT) {
|
||||||
|
if (curr[0] < USBH_DT_ENDPOINT_SIZE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iep->valid = 1;
|
||||||
|
iep->rem = rem;
|
||||||
|
iep->curr = curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ep_iter_init(generic_iterator_t *iep, const if_iterator_t *iif) {
|
||||||
|
iep->curr = iif->curr;
|
||||||
|
iep->rem = iif->rem;
|
||||||
|
ep_iter_next(iep);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cs_iter_next(generic_iterator_t *ics) {
|
||||||
|
const uint8_t *curr = ics->curr;
|
||||||
|
uint16_t rem = ics->rem;
|
||||||
|
|
||||||
|
ics->valid = 0;
|
||||||
|
|
||||||
|
if ((curr[0] < 2) || (rem < 2) || (rem < curr[0]))
|
||||||
|
return;
|
||||||
|
|
||||||
|
//for (;;) {
|
||||||
|
rem -= curr[0];
|
||||||
|
curr += curr[0];
|
||||||
|
|
||||||
|
if ((curr[0] < 2) || (rem < 2) || (rem < curr[0]))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((curr[1] == USBH_DT_INTERFACE_ASSOCIATION)
|
||||||
|
|| (curr[1] == USBH_DT_INTERFACE)
|
||||||
|
|| (curr[1] == USBH_DT_CONFIG)
|
||||||
|
|| (curr[1] == USBH_DT_ENDPOINT)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// break;
|
||||||
|
//}
|
||||||
|
|
||||||
|
ics->valid = 1;
|
||||||
|
ics->rem = rem;
|
||||||
|
ics->curr = curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cs_iter_init(generic_iterator_t *ics, const generic_iterator_t *iter) {
|
||||||
|
ics->curr = iter->curr;
|
||||||
|
ics->rem = iter->rem;
|
||||||
|
cs_iter_next(ics);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,717 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||||
|
Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hal.h"
|
||||||
|
#include "usbh.h"
|
||||||
|
|
||||||
|
#if HAL_USBH_USE_FTDI
|
||||||
|
|
||||||
|
#if !HAL_USE_USBH
|
||||||
|
#error "USBHFTDI needs USBH"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#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__)
|
||||||
|
#else
|
||||||
|
#define udbgf(f, ...) do {} while(0)
|
||||||
|
#define udbg(f, ...) do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USBHFTDI_DEBUG_ENABLE_INFO
|
||||||
|
#define uinfof(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
|
||||||
|
#define uinfo(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define uinfof(f, ...) do {} while(0)
|
||||||
|
#define uinfo(f, ...) do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USBHFTDI_DEBUG_ENABLE_WARNINGS
|
||||||
|
#define uwarnf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
|
||||||
|
#define uwarn(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define uwarnf(f, ...) do {} while(0)
|
||||||
|
#define uwarn(f, ...) do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USBHFTDI_DEBUG_ENABLE_ERRORS
|
||||||
|
#define uerrf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
|
||||||
|
#define uerr(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define uerrf(f, ...) do {} while(0)
|
||||||
|
#define uerr(f, ...) do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* USB Class driver loader for FTDI */
|
||||||
|
/*===========================================================================*/
|
||||||
|
USBHFTDIDriver USBHFTDID[HAL_USBHFTDI_MAX_INSTANCES];
|
||||||
|
|
||||||
|
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_load,
|
||||||
|
_ftdi_unload
|
||||||
|
};
|
||||||
|
|
||||||
|
const usbh_classdriverinfo_t usbhftdiClassDriverInfo = {
|
||||||
|
0xff, 0xff, 0xff, "FTDI", &class_driver_vmt
|
||||||
|
};
|
||||||
|
|
||||||
|
static USBHFTDIPortDriver *_find_port(void) {
|
||||||
|
uint8_t i;
|
||||||
|
for (i = 0; i < HAL_USBHFTDI_MAX_PORTS; i++) {
|
||||||
|
if (FTDIPD[i].ftdip == NULL)
|
||||||
|
return &FTDIPD[i];
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static usbh_baseclassdriver_t *_ftdi_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem) {
|
||||||
|
int i;
|
||||||
|
USBHFTDIDriver *ftdip;
|
||||||
|
|
||||||
|
if (dev->devDesc.idVendor != 0x0403) {
|
||||||
|
uerr("FTDI: Unrecognized VID");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (dev->devDesc.idProduct) {
|
||||||
|
case 0x6001:
|
||||||
|
case 0x6010:
|
||||||
|
case 0x6011:
|
||||||
|
case 0x6014:
|
||||||
|
case 0x6015:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
uerr("FTDI: Unrecognized PID");
|
||||||
|
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 * const)descriptor;
|
||||||
|
if (ifdesc->bInterfaceNumber != 0) {
|
||||||
|
uwarn("FTDI: Will allocate driver along with IF #0");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* alloc driver */
|
||||||
|
for (i = 0; i < HAL_USBHFTDI_MAX_INSTANCES; i++) {
|
||||||
|
if (USBHFTDID[i].dev == NULL) {
|
||||||
|
ftdip = &USBHFTDID[i];
|
||||||
|
goto alloc_ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uwarn("FTDI: Can't alloc driver");
|
||||||
|
|
||||||
|
/* can't alloc */
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
alloc_ok:
|
||||||
|
/* initialize the driver's variables */
|
||||||
|
ftdip->ports = 0;
|
||||||
|
switch (dev->devDesc.bcdDevice) {
|
||||||
|
case 0x200: //AM
|
||||||
|
uinfo("FTDI: Type A chip");
|
||||||
|
ftdip->type = USBHFTDI_TYPE_A;
|
||||||
|
break;
|
||||||
|
case 0x400: //BM
|
||||||
|
case 0x500: //2232C
|
||||||
|
case 0x600: //R
|
||||||
|
case 0x1000: //230X
|
||||||
|
uinfo("FTDI: Type B chip");
|
||||||
|
ftdip->type = USBHFTDI_TYPE_B;
|
||||||
|
break;
|
||||||
|
case 0x700: //2232H;
|
||||||
|
case 0x800: //4232H;
|
||||||
|
case 0x900: //232H;
|
||||||
|
uinfo("FTDI: Type H chip");
|
||||||
|
ftdip->type = USBHFTDI_TYPE_H;
|
||||||
|
default:
|
||||||
|
uerr("FTDI: Unrecognized chip type");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
usbhEPSetName(&dev->ctrl, "FTD[CTRL]");
|
||||||
|
|
||||||
|
/* parse the configuration descriptor */
|
||||||
|
generic_iterator_t iep, icfg;
|
||||||
|
if_iterator_t iif;
|
||||||
|
cfg_iter_init(&icfg, dev->fullConfigurationDescriptor, dev->basicConfigDesc.wTotalLength);
|
||||||
|
for (if_iter_init(&iif, &icfg); iif.valid; if_iter_next(&iif)) {
|
||||||
|
const usbh_interface_descriptor_t *const ifdesc = if_get(&iif);
|
||||||
|
uinfof("FTDI: Interface #%d", ifdesc->bInterfaceNumber);
|
||||||
|
|
||||||
|
USBHFTDIPortDriver *const prt = _find_port();
|
||||||
|
if (prt == NULL) {
|
||||||
|
uwarn("\tCan't alloc port for this interface");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
prt->ifnum = ifdesc->bInterfaceNumber;
|
||||||
|
prt->epin.status = USBH_EPSTATUS_UNINITIALIZED;
|
||||||
|
prt->epout.status = USBH_EPSTATUS_UNINITIALIZED;
|
||||||
|
|
||||||
|
for (ep_iter_init(&iep, &iif); iep.valid; ep_iter_next(&iep)) {
|
||||||
|
const usbh_endpoint_descriptor_t *const epdesc = ep_get(&iep);
|
||||||
|
if ((epdesc->bEndpointAddress & 0x80) && (epdesc->bmAttributes == USBH_EPTYPE_BULK)) {
|
||||||
|
uinfof("BULK IN endpoint found: bEndpointAddress=%02x", epdesc->bEndpointAddress);
|
||||||
|
usbhEPObjectInit(&prt->epin, dev, epdesc);
|
||||||
|
usbhEPSetName(&prt->epin, "FTD[BIN ]");
|
||||||
|
} else if (((epdesc->bEndpointAddress & 0x80) == 0)
|
||||||
|
&& (epdesc->bmAttributes == USBH_EPTYPE_BULK)) {
|
||||||
|
uinfof("BULK OUT endpoint found: bEndpointAddress=%02x", epdesc->bEndpointAddress);
|
||||||
|
usbhEPObjectInit(&prt->epout, dev, epdesc);
|
||||||
|
usbhEPSetName(&prt->epout, "FTD[BOUT]");
|
||||||
|
} else {
|
||||||
|
uinfof("unsupported endpoint found: bEndpointAddress=%02x, bmAttributes=%02x",
|
||||||
|
epdesc->bEndpointAddress, epdesc->bmAttributes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((prt->epin.status != USBH_EPSTATUS_CLOSED)
|
||||||
|
|| (prt->epout.status != USBH_EPSTATUS_CLOSED)) {
|
||||||
|
uwarn("\tCouldn't find endpoints; can't alloc port for this interface");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* link the new block driver to the list */
|
||||||
|
prt->next = ftdip->ports;
|
||||||
|
ftdip->ports = prt;
|
||||||
|
prt->ftdip = ftdip;
|
||||||
|
|
||||||
|
prt->state = USBHFTDIP_STATE_ACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (usbh_baseclassdriver_t *)ftdip;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _stop(USBHFTDIPortDriver *ftdipp);
|
||||||
|
static void _ftdi_unload(usbh_baseclassdriver_t *drv) {
|
||||||
|
osalDbgCheck(drv != NULL);
|
||||||
|
USBHFTDIDriver *const ftdip = (USBHFTDIDriver *)drv;
|
||||||
|
USBHFTDIPortDriver *ftdipp = ftdip->ports;
|
||||||
|
|
||||||
|
osalMutexLock(&ftdip->mtx);
|
||||||
|
while (ftdipp) {
|
||||||
|
_stop(ftdipp);
|
||||||
|
ftdipp = ftdipp->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
ftdipp = ftdip->ports;
|
||||||
|
osalSysLock();
|
||||||
|
while (ftdipp) {
|
||||||
|
USBHFTDIPortDriver *next = ftdipp->next;
|
||||||
|
usbhftdipObjectInit(ftdipp);
|
||||||
|
ftdipp = next;
|
||||||
|
}
|
||||||
|
osalSysUnlock();
|
||||||
|
osalMutexUnlock(&ftdip->mtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
USBHFTDIPortDriver FTDIPD[HAL_USBHFTDI_MAX_PORTS];
|
||||||
|
|
||||||
|
|
||||||
|
#define FTDI_COMMAND_RESET 0
|
||||||
|
#define FTDI_RESET_ALL 0
|
||||||
|
#define FTDI_RESET_PURGE_RX 1
|
||||||
|
#define FTDI_RESET_PURGE_TX 2
|
||||||
|
|
||||||
|
#define FTDI_COMMAND_SETFLOW 2
|
||||||
|
|
||||||
|
#define FTDI_COMMAND_SETBAUD 3
|
||||||
|
|
||||||
|
#define FTDI_COMMAND_SETDATA 4
|
||||||
|
#define FTDI_SETDATA_BREAK (0x1 << 14)
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#define FTDI_COMMAND_MODEMCTRL 1
|
||||||
|
#define FTDI_COMMAND_GETMODEMSTATUS 5 /* Retrieve current value of modem status register */
|
||||||
|
#define FTDI_COMMAND_SETEVENTCHAR 6 /* Set the event character */
|
||||||
|
#define FTDI_COMMAND_SETERRORCHAR 7 /* Set the error character */
|
||||||
|
#define FTDI_COMMAND_SETLATENCYTIMER 9 /* Set the latency timer */
|
||||||
|
#define FTDI_COMMAND_GETLATENCYTIMER 10 /* Get the latency timer */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DATA FORMAT
|
||||||
|
*
|
||||||
|
* IN Endpoint
|
||||||
|
*
|
||||||
|
* The device reserves the first two bytes of data on this endpoint to contain
|
||||||
|
* the current values of the modem and line status registers. In the absence of
|
||||||
|
* data, the device generates a message consisting of these two status bytes
|
||||||
|
* every 40 ms
|
||||||
|
*
|
||||||
|
* Byte 0: Modem Status
|
||||||
|
*
|
||||||
|
* Offset Description
|
||||||
|
* B0 Reserved - must be 1
|
||||||
|
* B1 Reserved - must be 0
|
||||||
|
* B2 Reserved - must be 0
|
||||||
|
* B3 Reserved - must be 0
|
||||||
|
* B4 Clear to Send (CTS)
|
||||||
|
* B5 Data Set Ready (DSR)
|
||||||
|
* B6 Ring Indicator (RI)
|
||||||
|
* B7 Receive Line Signal Detect (RLSD)
|
||||||
|
*
|
||||||
|
* Byte 1: Line Status
|
||||||
|
*
|
||||||
|
* Offset Description
|
||||||
|
* B0 Data Ready (DR)
|
||||||
|
* B1 Overrun Error (OE)
|
||||||
|
* B2 Parity Error (PE)
|
||||||
|
* B3 Framing Error (FE)
|
||||||
|
* B4 Break Interrupt (BI)
|
||||||
|
* B5 Transmitter Holding Register (THRE)
|
||||||
|
* B6 Transmitter Empty (TEMT)
|
||||||
|
* B7 Error in RCVR FIFO
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define FTDI_RS0_CTS (1 << 4)
|
||||||
|
#define FTDI_RS0_DSR (1 << 5)
|
||||||
|
#define FTDI_RS0_RI (1 << 6)
|
||||||
|
#define FTDI_RS0_RLSD (1 << 7)
|
||||||
|
|
||||||
|
#define FTDI_RS_DR 1
|
||||||
|
#define FTDI_RS_OE (1<<1)
|
||||||
|
#define FTDI_RS_PE (1<<2)
|
||||||
|
#define FTDI_RS_FE (1<<3)
|
||||||
|
#define FTDI_RS_BI (1<<4)
|
||||||
|
#define FTDI_RS_THRE (1<<5)
|
||||||
|
#define FTDI_RS_TEMT (1<<6)
|
||||||
|
#define FTDI_RS_FIFO (1<<7)
|
||||||
|
|
||||||
|
|
||||||
|
static usbh_urbstatus_t _ftdi_port_control(USBHFTDIPortDriver *ftdipp,
|
||||||
|
uint8_t bRequest, uint8_t wValue, uint8_t bHIndex, uint16_t wLength,
|
||||||
|
uint8_t *buff) {
|
||||||
|
|
||||||
|
static const uint8_t bmRequestType[] = {
|
||||||
|
USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE, //0 FTDI_COMMAND_RESET
|
||||||
|
USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE, //1 FTDI_COMMAND_MODEMCTRL
|
||||||
|
USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE, //2 FTDI_COMMAND_SETFLOW
|
||||||
|
USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE, //3 FTDI_COMMAND_SETBAUD
|
||||||
|
USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE, //4 FTDI_COMMAND_SETDATA
|
||||||
|
};
|
||||||
|
|
||||||
|
osalDbgCheck(bRequest < sizeof_array(bmRequestType));
|
||||||
|
osalDbgCheck(bRequest != 1);
|
||||||
|
|
||||||
|
const USBH_DEFINE_BUFFER(usbh_control_request_t, req) = {
|
||||||
|
bmRequestType[bRequest],
|
||||||
|
bRequest,
|
||||||
|
wValue,
|
||||||
|
(bHIndex << 8) | (ftdipp->ifnum + 1),
|
||||||
|
wLength
|
||||||
|
};
|
||||||
|
|
||||||
|
return usbhControlRequestExtended(ftdipp->ftdip->dev, &req, buff, NULL, MS2ST(1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t _get_divisor(uint32_t baud, usbhftdi_type_t type) {
|
||||||
|
static const uint8_t divfrac[8] = {0, 3, 2, 4, 1, 5, 6, 7};
|
||||||
|
uint32_t divisor;
|
||||||
|
|
||||||
|
if (type == USBHFTDI_TYPE_A) {
|
||||||
|
uint32_t divisor3 = ((48000000UL / 2) + baud / 2) / baud;
|
||||||
|
uinfof("FTDI: desired=%dbps, real=%dbps", baud, (48000000UL / 2) / divisor3);
|
||||||
|
if ((divisor3 & 0x7) == 7)
|
||||||
|
divisor3++; /* round x.7/8 up to x+1 */
|
||||||
|
|
||||||
|
divisor = divisor3 >> 3;
|
||||||
|
divisor3 &= 0x7;
|
||||||
|
if (divisor3 == 1)
|
||||||
|
divisor |= 0xc000;
|
||||||
|
else if (divisor3 >= 4)
|
||||||
|
divisor |= 0x4000;
|
||||||
|
else if (divisor3 != 0)
|
||||||
|
divisor |= 0x8000;
|
||||||
|
else if (divisor == 1)
|
||||||
|
divisor = 0; /* special case for maximum baud rate */
|
||||||
|
} else {
|
||||||
|
if (type == USBHFTDI_TYPE_B) {
|
||||||
|
divisor = ((48000000UL / 2) + baud / 2) / baud;
|
||||||
|
uinfof("FTDI: desired=%dbps, real=%dbps", baud, (48000000UL / 2) / divisor);
|
||||||
|
} else {
|
||||||
|
/* hi-speed baud rate is 10-bit sampling instead of 16-bit */
|
||||||
|
if (baud < 1200)
|
||||||
|
baud = 1200;
|
||||||
|
divisor = (120000000UL * 8 + baud * 5) / (baud * 10);
|
||||||
|
uinfof("FTDI: desired=%dbps, real=%dbps", baud, (120000000UL * 8) / divisor / 10);
|
||||||
|
}
|
||||||
|
divisor = (divisor >> 3) | (divfrac[divisor & 0x7] << 14);
|
||||||
|
|
||||||
|
/* Deal with special cases for highest baud rates. */
|
||||||
|
if (divisor == 1)
|
||||||
|
divisor = 0;
|
||||||
|
else if (divisor == 0x4001)
|
||||||
|
divisor = 1;
|
||||||
|
|
||||||
|
if (type == USBHFTDI_TYPE_H)
|
||||||
|
divisor |= 0x00020000;
|
||||||
|
}
|
||||||
|
return divisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
static usbh_urbstatus_t _set_baudrate(USBHFTDIPortDriver *ftdipp, uint32_t baudrate) {
|
||||||
|
uint32_t divisor = _get_divisor(baudrate, ftdipp->ftdip->type);
|
||||||
|
uint16_t wValue = (uint16_t)divisor;
|
||||||
|
uint16_t wIndex = (uint16_t)(divisor >> 16);
|
||||||
|
if (ftdipp->ftdip->dev->basicConfigDesc.bNumInterfaces > 1)
|
||||||
|
wIndex = (wIndex << 8) | (ftdipp->ifnum + 1);
|
||||||
|
|
||||||
|
const USBH_DEFINE_BUFFER(usbh_control_request_t, req) = {
|
||||||
|
USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE,
|
||||||
|
FTDI_COMMAND_SETBAUD,
|
||||||
|
wValue,
|
||||||
|
wIndex,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
return usbhControlRequestExtended(ftdipp->ftdip->dev, &req, NULL, NULL, MS2ST(1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void _submitOutI(USBHFTDIPortDriver *ftdipp, uint32_t len) {
|
||||||
|
udbgf("FTDI: Submit OUT %d", len);
|
||||||
|
ftdipp->oq_urb.requestedLength = len;
|
||||||
|
usbhURBObjectResetI(&ftdipp->oq_urb);
|
||||||
|
usbhURBSubmitI(&ftdipp->oq_urb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _out_cb(usbh_urb_t *urb) {
|
||||||
|
USBHFTDIPortDriver *const ftdipp = (USBHFTDIPortDriver *)urb->userData;
|
||||||
|
switch (urb->status) {
|
||||||
|
case USBH_URBSTATUS_OK:
|
||||||
|
ftdipp->oq_ptr = ftdipp->oq_buff;
|
||||||
|
ftdipp->oq_counter = 64;
|
||||||
|
chThdDequeueNextI(&ftdipp->oq_waiting, Q_OK);
|
||||||
|
return;
|
||||||
|
case USBH_URBSTATUS_DISCONNECTED:
|
||||||
|
uwarn("FTDI: URB OUT disconnected");
|
||||||
|
chThdDequeueNextI(&ftdipp->oq_waiting, Q_RESET);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
uerrf("FTDI: URB OUT status unexpected = %d", urb->status);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
usbhURBObjectResetI(&ftdipp->oq_urb);
|
||||||
|
usbhURBSubmitI(&ftdipp->oq_urb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t _write_timeout(USBHFTDIPortDriver *ftdipp, const uint8_t *bp,
|
||||||
|
size_t n, systime_t timeout) {
|
||||||
|
chDbgCheck(n > 0U);
|
||||||
|
|
||||||
|
size_t w = 0;
|
||||||
|
chSysLock();
|
||||||
|
while (true) {
|
||||||
|
if (ftdipp->state != USBHFTDIP_STATE_READY) {
|
||||||
|
chSysUnlock();
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
while (usbhURBIsBusy(&ftdipp->oq_urb)) {
|
||||||
|
if (chThdEnqueueTimeoutS(&ftdipp->oq_waiting, timeout) != Q_OK) {
|
||||||
|
chSysUnlock();
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*ftdipp->oq_ptr++ = *bp++;
|
||||||
|
if (--ftdipp->oq_counter == 0) {
|
||||||
|
_submitOutI(ftdipp, 64);
|
||||||
|
chSchRescheduleS();
|
||||||
|
}
|
||||||
|
chSysUnlock(); /* Gives a preemption chance in a controlled point.*/
|
||||||
|
|
||||||
|
w++;
|
||||||
|
if (--n == 0U)
|
||||||
|
return w;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static msg_t _put_timeout(USBHFTDIPortDriver *ftdipp, uint8_t b, systime_t timeout) {
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
if (ftdipp->state != USBHFTDIP_STATE_READY) {
|
||||||
|
chSysUnlock();
|
||||||
|
return Q_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (usbhURBIsBusy(&ftdipp->oq_urb)) {
|
||||||
|
msg_t msg = chThdEnqueueTimeoutS(&ftdipp->oq_waiting, timeout);
|
||||||
|
if (msg < Q_OK) {
|
||||||
|
chSysUnlock();
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*ftdipp->oq_ptr++ = b;
|
||||||
|
if (--ftdipp->oq_counter == 0) {
|
||||||
|
_submitOutI(ftdipp, 64);
|
||||||
|
chSchRescheduleS();
|
||||||
|
}
|
||||||
|
chSysUnlock();
|
||||||
|
return Q_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t _write(USBHFTDIPortDriver *ftdipp, const uint8_t *bp, size_t n) {
|
||||||
|
return _write_timeout(ftdipp, bp, n, TIME_INFINITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static msg_t _put(USBHFTDIPortDriver *ftdipp, uint8_t b) {
|
||||||
|
return _put_timeout(ftdipp, b, TIME_INFINITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _submitInI(USBHFTDIPortDriver *ftdipp) {
|
||||||
|
udbg("FTDI: Submit IN");
|
||||||
|
usbhURBObjectResetI(&ftdipp->iq_urb);
|
||||||
|
usbhURBSubmitI(&ftdipp->iq_urb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _in_cb(usbh_urb_t *urb) {
|
||||||
|
USBHFTDIPortDriver *const ftdipp = (USBHFTDIPortDriver *)urb->userData;
|
||||||
|
switch (urb->status) {
|
||||||
|
case USBH_URBSTATUS_OK:
|
||||||
|
if (urb->actualLength < 2) {
|
||||||
|
uwarnf("FTDI: URB IN actualLength = %d, < 2", urb->actualLength);
|
||||||
|
} else if (urb->actualLength > 2) {
|
||||||
|
udbgf("FTDI: URB IN data len=%d, status=%02x %02x",
|
||||||
|
urb->actualLength - 2,
|
||||||
|
((uint8_t *)urb->buff)[0],
|
||||||
|
((uint8_t *)urb->buff)[1]);
|
||||||
|
ftdipp->iq_ptr = ftdipp->iq_buff + 2;
|
||||||
|
ftdipp->iq_counter = urb->actualLength - 2;
|
||||||
|
chThdDequeueNextI(&ftdipp->iq_waiting, Q_OK);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
udbgf("FTDI: URB IN no data, status=%02x %02x",
|
||||||
|
((uint8_t *)urb->buff)[0],
|
||||||
|
((uint8_t *)urb->buff)[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case USBH_URBSTATUS_DISCONNECTED:
|
||||||
|
uwarn("FTDI: URB IN disconnected");
|
||||||
|
chThdDequeueNextI(&ftdipp->iq_waiting, Q_RESET);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
uerrf("FTDI: URB IN status unexpected = %d", urb->status);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_submitInI(ftdipp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t _read_timeout(USBHFTDIPortDriver *ftdipp, uint8_t *bp,
|
||||||
|
size_t n, systime_t timeout) {
|
||||||
|
size_t r = 0;
|
||||||
|
|
||||||
|
chDbgCheck(n > 0U);
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
while (true) {
|
||||||
|
if (ftdipp->state != USBHFTDIP_STATE_READY) {
|
||||||
|
chSysUnlock();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
while (ftdipp->iq_counter == 0) {
|
||||||
|
if (!usbhURBIsBusy(&ftdipp->iq_urb))
|
||||||
|
_submitInI(ftdipp);
|
||||||
|
if (chThdEnqueueTimeoutS(&ftdipp->iq_waiting, timeout) != Q_OK) {
|
||||||
|
chSysUnlock();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*bp++ = *ftdipp->iq_ptr++;
|
||||||
|
if (--ftdipp->iq_counter == 0) {
|
||||||
|
_submitInI(ftdipp);
|
||||||
|
chSchRescheduleS();
|
||||||
|
}
|
||||||
|
chSysUnlock();
|
||||||
|
|
||||||
|
r++;
|
||||||
|
if (--n == 0U)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static msg_t _get_timeout(USBHFTDIPortDriver *ftdipp, systime_t timeout) {
|
||||||
|
uint8_t b;
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
if (ftdipp->state != USBHFTDIP_STATE_READY) {
|
||||||
|
chSysUnlock();
|
||||||
|
return Q_RESET;
|
||||||
|
}
|
||||||
|
while (ftdipp->iq_counter == 0) {
|
||||||
|
if (!usbhURBIsBusy(&ftdipp->iq_urb))
|
||||||
|
_submitInI(ftdipp);
|
||||||
|
msg_t msg = chThdEnqueueTimeoutS(&ftdipp->iq_waiting, timeout);
|
||||||
|
if (msg < Q_OK) {
|
||||||
|
chSysUnlock();
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b = *ftdipp->iq_ptr++;
|
||||||
|
if (--ftdipp->iq_counter == 0) {
|
||||||
|
_submitInI(ftdipp);
|
||||||
|
chSchRescheduleS();
|
||||||
|
}
|
||||||
|
chSysUnlock();
|
||||||
|
|
||||||
|
return (msg_t)b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static msg_t _get(USBHFTDIPortDriver *ftdipp) {
|
||||||
|
return _get_timeout(ftdipp, TIME_INFINITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t _read(USBHFTDIPortDriver *ftdipp, uint8_t *bp, size_t n) {
|
||||||
|
return _read_timeout(ftdipp, bp, n, TIME_INFINITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _vt(void *p) {
|
||||||
|
USBHFTDIPortDriver *const ftdipp = (USBHFTDIPortDriver *)p;
|
||||||
|
chSysLockFromISR();
|
||||||
|
uint32_t len = ftdipp->oq_ptr - ftdipp->oq_buff;
|
||||||
|
if (len && !usbhURBIsBusy(&ftdipp->oq_urb)) {
|
||||||
|
_submitOutI(ftdipp, len);
|
||||||
|
}
|
||||||
|
if ((ftdipp->iq_counter == 0) && !usbhURBIsBusy(&ftdipp->iq_urb)) {
|
||||||
|
_submitInI(ftdipp);
|
||||||
|
}
|
||||||
|
chVTSetI(&ftdipp->vt, MS2ST(16), _vt, ftdipp);
|
||||||
|
chSysUnlockFromISR();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct FTDIPortDriverVMT async_channel_vmt = {
|
||||||
|
(size_t (*)(void *, const uint8_t *, size_t))_write,
|
||||||
|
(size_t (*)(void *, uint8_t *, size_t))_read,
|
||||||
|
(msg_t (*)(void *, uint8_t))_put,
|
||||||
|
(msg_t (*)(void *))_get,
|
||||||
|
(msg_t (*)(void *, uint8_t, systime_t))_put_timeout,
|
||||||
|
(msg_t (*)(void *, systime_t))_get_timeout,
|
||||||
|
(size_t (*)(void *, const uint8_t *, size_t, systime_t))_write_timeout,
|
||||||
|
(size_t (*)(void *, uint8_t *, size_t, systime_t))_read_timeout
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void _stop(USBHFTDIPortDriver *ftdipp) {
|
||||||
|
osalSysLock();
|
||||||
|
chVTResetI(&ftdipp->vt);
|
||||||
|
usbhEPCloseS(&ftdipp->epin);
|
||||||
|
usbhEPCloseS(&ftdipp->epout);
|
||||||
|
chThdDequeueAllI(&ftdipp->iq_waiting, Q_RESET);
|
||||||
|
chThdDequeueAllI(&ftdipp->oq_waiting, Q_RESET);
|
||||||
|
osalOsRescheduleS();
|
||||||
|
ftdipp->state = USBHFTDIP_STATE_ACTIVE;
|
||||||
|
osalSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void usbhftdipStop(USBHFTDIPortDriver *ftdipp) {
|
||||||
|
osalDbgCheck((ftdipp->state == USBHFTDIP_STATE_ACTIVE)
|
||||||
|
|| (ftdipp->state == USBHFTDIP_STATE_READY));
|
||||||
|
|
||||||
|
if (ftdipp->state == USBHFTDIP_STATE_ACTIVE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
osalMutexLock(&ftdipp->ftdip->mtx);
|
||||||
|
_stop(ftdipp);
|
||||||
|
osalMutexUnlock(&ftdipp->ftdip->mtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usbhftdipStart(USBHFTDIPortDriver *ftdipp, const USBHFTDIPortConfig *config) {
|
||||||
|
static const USBHFTDIPortConfig default_config = {
|
||||||
|
HAL_USBHFTDI_DEFAULT_SPEED,
|
||||||
|
HAL_USBHFTDI_DEFAULT_FRAMING,
|
||||||
|
HAL_USBHFTDI_DEFAULT_HANDSHAKE,
|
||||||
|
HAL_USBHFTDI_DEFAULT_XON,
|
||||||
|
HAL_USBHFTDI_DEFAULT_XOFF
|
||||||
|
};
|
||||||
|
|
||||||
|
osalDbgCheck((ftdipp->state == USBHFTDIP_STATE_ACTIVE)
|
||||||
|
|| (ftdipp->state == USBHFTDIP_STATE_READY));
|
||||||
|
|
||||||
|
if (ftdipp->state == USBHFTDIP_STATE_READY)
|
||||||
|
return;
|
||||||
|
|
||||||
|
osalMutexLock(&ftdipp->ftdip->mtx);
|
||||||
|
if (config == NULL)
|
||||||
|
config = &default_config;
|
||||||
|
|
||||||
|
uint16_t wValue = 0;
|
||||||
|
_ftdi_port_control(ftdipp, FTDI_COMMAND_RESET, FTDI_RESET_ALL, 0, 0, NULL);
|
||||||
|
_set_baudrate(ftdipp, config->speed);
|
||||||
|
_ftdi_port_control(ftdipp, FTDI_COMMAND_SETDATA, config->framing, 0, 0, NULL);
|
||||||
|
if (config->handshake & USBHFTDI_HANDSHAKE_XON_XOFF)
|
||||||
|
wValue = (config->xoff_character << 8) | config->xon_character;
|
||||||
|
_ftdi_port_control(ftdipp, FTDI_COMMAND_SETFLOW, wValue, config->handshake, 0, NULL);
|
||||||
|
|
||||||
|
usbhURBObjectInit(&ftdipp->oq_urb, &ftdipp->epout, _out_cb, ftdipp, ftdipp->oq_buff, 0);
|
||||||
|
chThdQueueObjectInit(&ftdipp->oq_waiting);
|
||||||
|
ftdipp->oq_counter = 64;
|
||||||
|
ftdipp->oq_ptr = ftdipp->oq_buff;
|
||||||
|
usbhEPOpen(&ftdipp->epout);
|
||||||
|
|
||||||
|
usbhURBObjectInit(&ftdipp->iq_urb, &ftdipp->epin, _in_cb, ftdipp, ftdipp->iq_buff, 64);
|
||||||
|
chThdQueueObjectInit(&ftdipp->iq_waiting);
|
||||||
|
ftdipp->iq_counter = 0;
|
||||||
|
ftdipp->iq_ptr = ftdipp->iq_buff;
|
||||||
|
usbhEPOpen(&ftdipp->epin);
|
||||||
|
osalSysLock();
|
||||||
|
usbhURBSubmitI(&ftdipp->iq_urb);
|
||||||
|
osalSysUnlock();
|
||||||
|
|
||||||
|
chVTObjectInit(&ftdipp->vt);
|
||||||
|
chVTSet(&ftdipp->vt, MS2ST(16), _vt, ftdipp);
|
||||||
|
|
||||||
|
ftdipp->state = USBHFTDIP_STATE_READY;
|
||||||
|
osalMutexUnlock(&ftdipp->ftdip->mtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usbhftdiObjectInit(USBHFTDIDriver *ftdip) {
|
||||||
|
osalDbgCheck(ftdip != NULL);
|
||||||
|
memset(ftdip, 0, sizeof(*ftdip));
|
||||||
|
ftdip->info = &usbhftdiClassDriverInfo;
|
||||||
|
osalMutexObjectInit(&ftdip->mtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usbhftdipObjectInit(USBHFTDIPortDriver *ftdipp) {
|
||||||
|
osalDbgCheck(ftdipp != NULL);
|
||||||
|
memset(ftdipp, 0, sizeof(*ftdipp));
|
||||||
|
ftdipp->vmt = &async_channel_vmt;
|
||||||
|
ftdipp->state = USBHFTDIP_STATE_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,302 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||||
|
Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hal.h"
|
||||||
|
#include "usbh.h"
|
||||||
|
#include "usbh/internal.h"
|
||||||
|
|
||||||
|
#if HAL_USBH_USE_HUB
|
||||||
|
|
||||||
|
#if !HAL_USE_USBH
|
||||||
|
#error "USBHHUB needs HAL_USE_USBH"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "usbh/dev/hub.h"
|
||||||
|
|
||||||
|
#if USBHHUB_DEBUG_ENABLE_TRACE
|
||||||
|
#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
|
||||||
|
#define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define udbgf(f, ...) do {} while(0)
|
||||||
|
#define udbg(f, ...) do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USBHHUB_DEBUG_ENABLE_INFO
|
||||||
|
#define uinfof(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
|
||||||
|
#define uinfo(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define uinfof(f, ...) do {} while(0)
|
||||||
|
#define uinfo(f, ...) do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USBHHUB_DEBUG_ENABLE_WARNINGS
|
||||||
|
#define uwarnf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
|
||||||
|
#define uwarn(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define uwarnf(f, ...) do {} while(0)
|
||||||
|
#define uwarn(f, ...) do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USBHHUB_DEBUG_ENABLE_ERRORS
|
||||||
|
#define uerrf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
|
||||||
|
#define uerr(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define uerrf(f, ...) do {} while(0)
|
||||||
|
#define uerr(f, ...) do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
USBHHubDriver USBHHUBD[HAL_USBHHUB_MAX_INSTANCES];
|
||||||
|
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 const usbh_classdriver_vmt_t usbhhubClassDriverVMT = {
|
||||||
|
hub_load,
|
||||||
|
hub_unload
|
||||||
|
};
|
||||||
|
const usbh_classdriverinfo_t usbhhubClassDriverInfo = {
|
||||||
|
0x09, 0x00, -1, "HUB", &usbhhubClassDriverVMT
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void _usbhub_port_object_init(usbh_port_t *port, USBHDriver *usbh,
|
||||||
|
USBHHubDriver *hub, uint8_t number) {
|
||||||
|
memset(port, 0, sizeof(*port));
|
||||||
|
port->number = number;
|
||||||
|
port->device.host = usbh;
|
||||||
|
port->hub = hub;
|
||||||
|
}
|
||||||
|
|
||||||
|
usbh_urbstatus_t usbhhubControlRequest(USBHDriver *host, USBHHubDriver *hub,
|
||||||
|
uint8_t bmRequestType,
|
||||||
|
uint8_t bRequest,
|
||||||
|
uint16_t wValue,
|
||||||
|
uint16_t wIndex,
|
||||||
|
uint16_t wLength,
|
||||||
|
uint8_t *buf) {
|
||||||
|
if (hub == NULL)
|
||||||
|
return usbh_lld_root_hub_request(host, bmRequestType, bRequest, wValue, wIndex, wLength, buf);
|
||||||
|
|
||||||
|
return usbhControlRequest(hub->dev,
|
||||||
|
bmRequestType, bRequest, wValue, wIndex, wLength, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void _urb_complete(usbh_urb_t *urb) {
|
||||||
|
|
||||||
|
USBHHubDriver *const hubdp = (USBHHubDriver *)urb->userData;
|
||||||
|
switch (urb->status) {
|
||||||
|
case USBH_URBSTATUS_TIMEOUT:
|
||||||
|
/* the device NAKed */
|
||||||
|
udbg("HUB: no info");
|
||||||
|
hubdp->statuschange = 0;
|
||||||
|
break;
|
||||||
|
case USBH_URBSTATUS_OK: {
|
||||||
|
uint8_t len = hubdp->hubDesc.bNbrPorts / 8 + 1;
|
||||||
|
if (urb->actualLength != len) {
|
||||||
|
uwarnf("Expected %d status change bytes but got %d", len, urb->actualLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (urb->actualLength < len)
|
||||||
|
len = urb->actualLength;
|
||||||
|
|
||||||
|
if (len > 4)
|
||||||
|
len = 4;
|
||||||
|
|
||||||
|
uint8_t *sc = (uint8_t *)&hubdp->statuschange;
|
||||||
|
uint8_t *r = hubdp->scbuff;
|
||||||
|
while (len--)
|
||||||
|
*sc++ |= *r++;
|
||||||
|
|
||||||
|
uinfof("HUB: change, %08x", hubdp->statuschange);
|
||||||
|
} break;
|
||||||
|
case USBH_URBSTATUS_DISCONNECTED:
|
||||||
|
uwarn("HUB: URB disconnected, aborting poll");
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
uerrf("HUB: URB status unexpected = %d", urb->status);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
usbhURBObjectResetI(urb);
|
||||||
|
usbhURBSubmitI(urb);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
generic_iterator_t iep, icfg;
|
||||||
|
if_iterator_t iif;
|
||||||
|
|
||||||
|
cfg_iter_init(&icfg, dev->fullConfigurationDescriptor,
|
||||||
|
dev->basicConfigDesc.wTotalLength);
|
||||||
|
|
||||||
|
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)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ep_iter_init(&iep, &iif);
|
||||||
|
if (!iep.valid)
|
||||||
|
return NULL;
|
||||||
|
const usbh_endpoint_descriptor_t *const epdesc = ep_get(&iep);
|
||||||
|
if ((epdesc->bmAttributes & 0x03) != USBH_EPTYPE_INT) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* alloc driver */
|
||||||
|
for (i = 0; i < HAL_USBHHUB_MAX_INSTANCES; i++) {
|
||||||
|
if (USBHHUBD[i].dev == NULL) {
|
||||||
|
hubdp = &USBHHUBD[i];
|
||||||
|
goto alloc_ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uwarn("Can't alloc HUB driver");
|
||||||
|
|
||||||
|
/* can't alloc */
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
alloc_ok:
|
||||||
|
/* initialize the driver's variables */
|
||||||
|
hubdp->epint.status = USBH_EPSTATUS_UNINITIALIZED;
|
||||||
|
hubdp->dev = dev;
|
||||||
|
hubdp->ports = 0;
|
||||||
|
|
||||||
|
usbhEPSetName(&dev->ctrl, "HUB[CTRL]");
|
||||||
|
|
||||||
|
/* read Hub descriptor */
|
||||||
|
uinfo("Read Hub descriptor");
|
||||||
|
if (usbhhubControlRequest(dev->host, hubdp,
|
||||||
|
USBH_REQTYPE_IN | USBH_REQTYPE_CLASS | USBH_REQTYPE_DEVICE,
|
||||||
|
USBH_REQ_GET_DESCRIPTOR,
|
||||||
|
(USBH_DT_HUB << 8), 0, sizeof(hubdp->hubDesc),
|
||||||
|
(uint8_t *)&hubdp->hubDesc) != USBH_URBSTATUS_OK) {
|
||||||
|
hubdp->dev = NULL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const usbh_hub_descriptor_t *const hubdesc = &hubdp->hubDesc;
|
||||||
|
|
||||||
|
uinfof("Hub descriptor loaded; %d ports, wHubCharacteristics=%04x, bPwrOn2PwrGood=%d, bHubContrCurrent=%d",
|
||||||
|
hubdesc->bNbrPorts,
|
||||||
|
hubdesc->wHubCharacteristics,
|
||||||
|
hubdesc->bPwrOn2PwrGood,
|
||||||
|
hubdesc->bHubContrCurrent);
|
||||||
|
|
||||||
|
/* Alloc ports */
|
||||||
|
uint8_t ports = hubdesc->bNbrPorts;
|
||||||
|
for (i = 0; (ports > 0) && (i < HAL_USBHHUB_MAX_PORTS); i++) {
|
||||||
|
if (USBHPorts[i].hub == NULL) {
|
||||||
|
uinfof("Alloc port %d", ports);
|
||||||
|
_usbhub_port_object_init(&USBHPorts[i], dev->host, hubdp, ports);
|
||||||
|
USBHPorts[i].next = hubdp->ports;
|
||||||
|
hubdp->ports = &USBHPorts[i];
|
||||||
|
--ports;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ports) {
|
||||||
|
uwarn("Could not alloc all ports");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* link hub to the host's list */
|
||||||
|
list_add_tail(&hubdp->node, &dev->host->hubs);
|
||||||
|
|
||||||
|
/* enable power to ports */
|
||||||
|
usbh_port_t *port = hubdp->ports;
|
||||||
|
while (port) {
|
||||||
|
uinfof("Enable power for port %d", port->number);
|
||||||
|
usbhhubSetFeaturePort(port, USBH_PORT_FEAT_POWER);
|
||||||
|
port = port->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hubdesc->bPwrOn2PwrGood)
|
||||||
|
osalThreadSleepMilliseconds(2 * hubdesc->bPwrOn2PwrGood);
|
||||||
|
|
||||||
|
/* initialize the status change endpoint and trigger the first transfer */
|
||||||
|
usbhEPObjectInit(&hubdp->epint, dev, epdesc);
|
||||||
|
usbhEPSetName(&hubdp->epint, "HUB[INT ]");
|
||||||
|
usbhEPOpen(&hubdp->epint);
|
||||||
|
|
||||||
|
usbhURBObjectInit(&hubdp->urb, &hubdp->epint,
|
||||||
|
_urb_complete, hubdp, hubdp->scbuff,
|
||||||
|
(hubdesc->bNbrPorts + 8) / 8);
|
||||||
|
|
||||||
|
osalSysLock();
|
||||||
|
usbhURBSubmitI(&hubdp->urb);
|
||||||
|
osalOsRescheduleS();
|
||||||
|
osalSysUnlock();
|
||||||
|
|
||||||
|
return (usbh_baseclassdriver_t *)hubdp;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
/* de-alloc ports and unload drivers */
|
||||||
|
usbh_port_t *port = hubdp->ports;
|
||||||
|
while (port) {
|
||||||
|
_usbh_port_disconnected(port);
|
||||||
|
port->hub = NULL;
|
||||||
|
port = port->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unlink the hub from the host's list */
|
||||||
|
list_del(&hubdp->node);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void usbhhubObjectInit(USBHHubDriver *hubdp) {
|
||||||
|
osalDbgCheck(hubdp != NULL);
|
||||||
|
memset(hubdp, 0, sizeof(*hubdp));
|
||||||
|
hubdp->info = &usbhhubClassDriverInfo;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
#if HAL_USE_USBH
|
||||||
|
void _usbhub_port_object_init(usbh_port_t *port, USBHDriver *usbh, uint8_t number) {
|
||||||
|
memset(port, 0, sizeof(*port));
|
||||||
|
port->number = number;
|
||||||
|
port->device.host = usbh;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,939 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||||
|
Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hal.h"
|
||||||
|
#include "usbh.h"
|
||||||
|
|
||||||
|
#if HAL_USBH_USE_MSD
|
||||||
|
|
||||||
|
#if !HAL_USE_USBH
|
||||||
|
#error "USBHMSD needs USBH"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#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__)
|
||||||
|
#else
|
||||||
|
#define udbgf(f, ...) do {} while(0)
|
||||||
|
#define udbg(f, ...) do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USBHMSD_DEBUG_ENABLE_INFO
|
||||||
|
#define uinfof(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
|
||||||
|
#define uinfo(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define uinfof(f, ...) do {} while(0)
|
||||||
|
#define uinfo(f, ...) do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USBHMSD_DEBUG_ENABLE_WARNINGS
|
||||||
|
#define uwarnf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
|
||||||
|
#define uwarn(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define uwarnf(f, ...) do {} while(0)
|
||||||
|
#define uwarn(f, ...) do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USBHMSD_DEBUG_ENABLE_ERRORS
|
||||||
|
#define uerrf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
|
||||||
|
#define uerr(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define uerrf(f, ...) do {} while(0)
|
||||||
|
#define uerr(f, ...) do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* USB Class driver loader for MSD */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
USBHMassStorageDriver USBHMSD[HAL_USBHMSD_MAX_INSTANCES];
|
||||||
|
|
||||||
|
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_load,
|
||||||
|
_msd_unload
|
||||||
|
};
|
||||||
|
|
||||||
|
const usbh_classdriverinfo_t usbhmsdClassDriverInfo = {
|
||||||
|
0x08, 0x06, 0x50, "MSD", &class_driver_vmt
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MSD_REQ_RESET 0xFF
|
||||||
|
#define MSD_GET_MAX_LUN 0xFE
|
||||||
|
|
||||||
|
static usbh_baseclassdriver_t *_msd_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem) {
|
||||||
|
int i;
|
||||||
|
USBHMassStorageDriver *msdp;
|
||||||
|
uint8_t luns; // should declare it here to eliminate 'control bypass initialization' warning
|
||||||
|
usbh_urbstatus_t stat; // should declare it here to eliminate 'control bypass initialization' warning
|
||||||
|
|
||||||
|
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->bAlternateSetting != 0)
|
||||||
|
|| (ifdesc->bNumEndpoints < 2)
|
||||||
|
|| (ifdesc->bInterfaceSubClass != 0x06)
|
||||||
|
|| (ifdesc->bInterfaceProtocol != 0x50)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* alloc driver */
|
||||||
|
for (i = 0; i < HAL_USBHMSD_MAX_INSTANCES; i++) {
|
||||||
|
if (USBHMSD[i].dev == NULL) {
|
||||||
|
msdp = &USBHMSD[i];
|
||||||
|
goto alloc_ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uwarn("Can't alloc MSD driver");
|
||||||
|
|
||||||
|
/* can't alloc */
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
alloc_ok:
|
||||||
|
/* initialize the driver's variables */
|
||||||
|
msdp->epin.status = USBH_EPSTATUS_UNINITIALIZED;
|
||||||
|
msdp->epout.status = USBH_EPSTATUS_UNINITIALIZED;
|
||||||
|
msdp->max_lun = 0;
|
||||||
|
msdp->tag = 0;
|
||||||
|
msdp->luns = 0;
|
||||||
|
msdp->ifnum = ifdesc->bInterfaceNumber;
|
||||||
|
usbhEPSetName(&dev->ctrl, "MSD[CTRL]");
|
||||||
|
|
||||||
|
/* parse the configuration descriptor */
|
||||||
|
if_iterator_t iif;
|
||||||
|
generic_iterator_t iep;
|
||||||
|
iif.iad = 0;
|
||||||
|
iif.curr = descriptor;
|
||||||
|
iif.rem = rem;
|
||||||
|
for (ep_iter_init(&iep, &iif); iep.valid; ep_iter_next(&iep)) {
|
||||||
|
const usbh_endpoint_descriptor_t *const epdesc = ep_get(&iep);
|
||||||
|
if ((epdesc->bEndpointAddress & 0x80) && (epdesc->bmAttributes == USBH_EPTYPE_BULK)) {
|
||||||
|
uinfof("BULK IN endpoint found: bEndpointAddress=%02x", epdesc->bEndpointAddress);
|
||||||
|
usbhEPObjectInit(&msdp->epin, dev, epdesc);
|
||||||
|
usbhEPSetName(&msdp->epin, "MSD[BIN ]");
|
||||||
|
} else if (((epdesc->bEndpointAddress & 0x80) == 0)
|
||||||
|
&& (epdesc->bmAttributes == USBH_EPTYPE_BULK)) {
|
||||||
|
uinfof("BULK OUT endpoint found: bEndpointAddress=%02x", epdesc->bEndpointAddress);
|
||||||
|
usbhEPObjectInit(&msdp->epout, dev, epdesc);
|
||||||
|
usbhEPSetName(&msdp->epout, "MSD[BOUT]");
|
||||||
|
} else {
|
||||||
|
uinfof("unsupported endpoint found: bEndpointAddress=%02x, bmAttributes=%02x",
|
||||||
|
epdesc->bEndpointAddress, epdesc->bmAttributes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((msdp->epin.status != USBH_EPSTATUS_CLOSED) || (msdp->epout.status != USBH_EPSTATUS_CLOSED)) {
|
||||||
|
goto deinit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read the number of LUNs */
|
||||||
|
uinfo("Reading Max LUN:");
|
||||||
|
USBH_DEFINE_BUFFER(uint8_t, buff[4]);
|
||||||
|
stat = usbhControlRequest(dev,
|
||||||
|
USBH_CLASSIN(USBH_REQTYPE_INTERFACE, MSD_GET_MAX_LUN, 0, msdp->ifnum),
|
||||||
|
1, buff);
|
||||||
|
if (stat == USBH_URBSTATUS_OK) {
|
||||||
|
msdp->max_lun = buff[0] + 1;
|
||||||
|
uinfof("\tmax_lun = %d", msdp->max_lun);
|
||||||
|
if (msdp->max_lun > HAL_USBHMSD_MAX_LUNS) {
|
||||||
|
msdp->max_lun = HAL_USBHMSD_MAX_LUNS;
|
||||||
|
uwarnf("\tUsing max_lun = %d", msdp->max_lun);
|
||||||
|
}
|
||||||
|
} else if (stat == USBH_URBSTATUS_STALL) {
|
||||||
|
uwarn("\tStall, max_lun = 1");
|
||||||
|
msdp->max_lun = 1;
|
||||||
|
} else {
|
||||||
|
uerr("\tError");
|
||||||
|
goto deinit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open the bulk IN/OUT endpoints */
|
||||||
|
usbhEPOpen(&msdp->epin);
|
||||||
|
usbhEPOpen(&msdp->epout);
|
||||||
|
|
||||||
|
/* Alloc one block device per logical unit found */
|
||||||
|
luns = msdp->max_lun;
|
||||||
|
for (i = 0; (luns > 0) && (i < HAL_USBHMSD_MAX_LUNS); i++) {
|
||||||
|
if (MSBLKD[i].msdp == NULL) {
|
||||||
|
/* link the new block driver to the list */
|
||||||
|
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) */
|
||||||
|
usbhmsdLUNConnect(&MSBLKD[i]);
|
||||||
|
luns--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (usbh_baseclassdriver_t *)msdp;
|
||||||
|
|
||||||
|
deinit:
|
||||||
|
/* Here, the enpoints are closed, and the driver is unlinked */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _msd_unload(usbh_baseclassdriver_t *drv) {
|
||||||
|
osalDbgCheck(drv != NULL);
|
||||||
|
USBHMassStorageDriver *const msdp = (USBHMassStorageDriver *)drv;
|
||||||
|
USBHMassStorageLUNDriver *lunp = msdp->luns;
|
||||||
|
|
||||||
|
osalMutexLock(&msdp->mtx);
|
||||||
|
osalSysLock();
|
||||||
|
usbhEPCloseS(&msdp->epin);
|
||||||
|
usbhEPCloseS(&msdp->epout);
|
||||||
|
while (lunp) {
|
||||||
|
lunp->state = BLK_STOP;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* MSD Class driver operations (Bulk-Only transport) */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* USB Bulk Only Transport SCSI Command block wrapper */
|
||||||
|
PACKED_STRUCT {
|
||||||
|
uint32_t dCBWSignature;
|
||||||
|
uint32_t dCBWTag;
|
||||||
|
uint32_t dCBWDataTransferLength;
|
||||||
|
uint8_t bmCBWFlags;
|
||||||
|
uint8_t bCBWLUN;
|
||||||
|
uint8_t bCBWCBLength;
|
||||||
|
uint8_t CBWCB[16];
|
||||||
|
} msd_cbw_t;
|
||||||
|
#define MSD_CBW_SIGNATURE 0x43425355
|
||||||
|
#define MSD_CBWFLAGS_D2H 0x80
|
||||||
|
#define MSD_CBWFLAGS_H2D 0x00
|
||||||
|
|
||||||
|
|
||||||
|
/* USB Bulk Only Transport SCSI Command status wrapper */
|
||||||
|
PACKED_STRUCT {
|
||||||
|
uint32_t dCSWSignature;
|
||||||
|
uint32_t dCSWTag;
|
||||||
|
uint32_t dCSWDataResidue;
|
||||||
|
uint8_t bCSWStatus;
|
||||||
|
} msd_csw_t;
|
||||||
|
#define MSD_CSW_SIGNATURE 0x53425355
|
||||||
|
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
msd_cbw_t cbw;
|
||||||
|
msd_csw_t csw;
|
||||||
|
} msd_transaction_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MSD_TRANSACTIONRESULT_OK,
|
||||||
|
MSD_TRANSACTIONRESULT_DISCONNECTED,
|
||||||
|
MSD_TRANSACTIONRESULT_STALL,
|
||||||
|
MSD_TRANSACTIONRESULT_BUS_ERROR,
|
||||||
|
MSD_TRANSACTIONRESULT_SYNC_ERROR
|
||||||
|
} msd_transaction_result_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MSD_COMMANDRESULT_PASSED = 0,
|
||||||
|
MSD_COMMANDRESULT_FAILED = 1,
|
||||||
|
MSD_COMMANDRESULT_PHASE_ERROR = 2
|
||||||
|
} msd_command_result_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
msd_transaction_result_t tres;
|
||||||
|
msd_command_result_t cres;
|
||||||
|
} msd_result_t;
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------------------------------------------------- */
|
||||||
|
/* SCSI Commands */
|
||||||
|
/* ----------------------------------------------------- */
|
||||||
|
|
||||||
|
/* Read 10 and Write 10 */
|
||||||
|
#define SCSI_CMD_READ_10 0x28
|
||||||
|
#define SCSI_CMD_WRITE_10 0x2A
|
||||||
|
|
||||||
|
/* Request sense */
|
||||||
|
#define SCSI_CMD_REQUEST_SENSE 0x03
|
||||||
|
PACKED_STRUCT {
|
||||||
|
uint8_t byte[18];
|
||||||
|
} scsi_sense_response_t;
|
||||||
|
|
||||||
|
#define SCSI_SENSE_KEY_GOOD 0x00
|
||||||
|
#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01
|
||||||
|
#define SCSI_SENSE_KEY_NOT_READY 0x02
|
||||||
|
#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03
|
||||||
|
#define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04
|
||||||
|
#define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05
|
||||||
|
#define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06
|
||||||
|
#define SCSI_SENSE_KEY_DATA_PROTECT 0x07
|
||||||
|
#define SCSI_SENSE_KEY_BLANK_CHECK 0x08
|
||||||
|
#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09
|
||||||
|
#define SCSI_SENSE_KEY_COPY_ABORTED 0x0A
|
||||||
|
#define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B
|
||||||
|
#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D
|
||||||
|
#define SCSI_SENSE_KEY_MISCOMPARE 0x0E
|
||||||
|
#define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION 0x00
|
||||||
|
#define SCSI_ASENSE_LOGICAL_UNIT_NOT_READY 0x04
|
||||||
|
#define SCSI_ASENSE_INVALID_FIELD_IN_CDB 0x24
|
||||||
|
#define SCSI_ASENSE_NOT_READY_TO_READY_CHANGE 0x28
|
||||||
|
#define SCSI_ASENSE_WRITE_PROTECTED 0x27
|
||||||
|
#define SCSI_ASENSE_FORMAT_ERROR 0x31
|
||||||
|
#define SCSI_ASENSE_INVALID_COMMAND 0x20
|
||||||
|
#define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21
|
||||||
|
#define SCSI_ASENSE_MEDIUM_NOT_PRESENT 0x3A
|
||||||
|
#define SCSI_ASENSEQ_NO_QUALIFIER 0x00
|
||||||
|
#define SCSI_ASENSEQ_FORMAT_COMMAND_FAILED 0x01
|
||||||
|
#define SCSI_ASENSEQ_INITIALIZING_COMMAND_REQUIRED 0x02
|
||||||
|
#define SCSI_ASENSEQ_OPERATION_IN_PROGRESS 0x07
|
||||||
|
|
||||||
|
/* Inquiry */
|
||||||
|
#define SCSI_CMD_INQUIRY 0x12
|
||||||
|
PACKED_STRUCT {
|
||||||
|
uint8_t peripheral;
|
||||||
|
uint8_t removable;
|
||||||
|
uint8_t version;
|
||||||
|
uint8_t response_data_format;
|
||||||
|
uint8_t additional_length;
|
||||||
|
uint8_t sccstp;
|
||||||
|
uint8_t bqueetc;
|
||||||
|
uint8_t cmdque;
|
||||||
|
uint8_t vendorID[8];
|
||||||
|
uint8_t productID[16];
|
||||||
|
uint8_t productRev[4];
|
||||||
|
} scsi_inquiry_response_t;
|
||||||
|
|
||||||
|
/* Read Capacity 10 */
|
||||||
|
#define SCSI_CMD_READ_CAPACITY_10 0x25
|
||||||
|
PACKED_STRUCT {
|
||||||
|
uint32_t last_block_addr;
|
||||||
|
uint32_t block_size;
|
||||||
|
} scsi_readcapacity10_response_t;
|
||||||
|
|
||||||
|
/* Start/Stop Unit */
|
||||||
|
#define SCSI_CMD_START_STOP_UNIT 0x1B
|
||||||
|
PACKED_STRUCT {
|
||||||
|
uint8_t op_code;
|
||||||
|
uint8_t lun_immed;
|
||||||
|
uint8_t res1;
|
||||||
|
uint8_t res2;
|
||||||
|
uint8_t loej_start;
|
||||||
|
uint8_t control;
|
||||||
|
} scsi_startstopunit_request_t;
|
||||||
|
|
||||||
|
/* test unit ready */
|
||||||
|
#define SCSI_CMD_TEST_UNIT_READY 0x00
|
||||||
|
|
||||||
|
/* Other commands, TODO: use or remove them
|
||||||
|
#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
|
||||||
|
#define SCSI_CMD_VERIFY_10 0x2F
|
||||||
|
#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D
|
||||||
|
#define SCSI_CMD_MODE_SENSE_6 0x1A
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline void _prepare_cbw(msd_transaction_t *tran, USBHMassStorageLUNDriver *lunp) {
|
||||||
|
tran->cbw.bCBWLUN = (uint8_t)(lunp - &lunp->msdp->luns[0]);
|
||||||
|
memset(&tran->cbw.CBWCB, 0, sizeof(tran->cbw.CBWCB));
|
||||||
|
}
|
||||||
|
|
||||||
|
static msd_transaction_result_t _msd_transaction(msd_transaction_t *tran, USBHMassStorageLUNDriver *lunp, void *data) {
|
||||||
|
|
||||||
|
uint32_t actual_len;
|
||||||
|
usbh_urbstatus_t status;
|
||||||
|
|
||||||
|
tran->cbw.dCBWSignature = MSD_CBW_SIGNATURE;
|
||||||
|
tran->cbw.dCBWTag = ++lunp->msdp->tag;
|
||||||
|
|
||||||
|
/* control phase */
|
||||||
|
status = usbhBulkTransfer(&lunp->msdp->epout, &tran->cbw,
|
||||||
|
sizeof(tran->cbw), &actual_len, MS2ST(1000));
|
||||||
|
|
||||||
|
if (status == USBH_URBSTATUS_CANCELLED) {
|
||||||
|
uerr("\tMSD: Control phase: USBH_URBSTATUS_CANCELLED");
|
||||||
|
return MSD_TRANSACTIONRESULT_DISCONNECTED;
|
||||||
|
} else if (status == USBH_URBSTATUS_STALL) {
|
||||||
|
uerr("\tMSD: Control phase: USBH_URBSTATUS_STALL");
|
||||||
|
return MSD_TRANSACTIONRESULT_STALL;
|
||||||
|
} else if (status != USBH_URBSTATUS_OK) {
|
||||||
|
uerrf("\tMSD: Control phase: status = %d, != OK", status);
|
||||||
|
return MSD_TRANSACTIONRESULT_BUS_ERROR;
|
||||||
|
} else if (actual_len != sizeof(tran->cbw)) {
|
||||||
|
uerrf("\tMSD: Control phase: wrong actual_len = %d", actual_len);
|
||||||
|
return MSD_TRANSACTIONRESULT_BUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* data phase */
|
||||||
|
if (tran->cbw.dCBWDataTransferLength) {
|
||||||
|
status = usbhBulkTransfer(
|
||||||
|
tran->cbw.bmCBWFlags & MSD_CBWFLAGS_D2H ? &lunp->msdp->epin : &lunp->msdp->epout,
|
||||||
|
data,
|
||||||
|
tran->cbw.dCBWDataTransferLength,
|
||||||
|
&actual_len, MS2ST(20000));
|
||||||
|
|
||||||
|
if (status == USBH_URBSTATUS_CANCELLED) {
|
||||||
|
uerr("\tMSD: Data phase: USBH_URBSTATUS_CANCELLED");
|
||||||
|
return MSD_TRANSACTIONRESULT_DISCONNECTED;
|
||||||
|
} else if (status == USBH_URBSTATUS_STALL) {
|
||||||
|
uerr("\tMSD: Data phase: USBH_URBSTATUS_STALL");
|
||||||
|
return MSD_TRANSACTIONRESULT_STALL;
|
||||||
|
} else if (status != USBH_URBSTATUS_OK) {
|
||||||
|
uerrf("\tMSD: Data phase: status = %d, != OK", status);
|
||||||
|
return MSD_TRANSACTIONRESULT_BUS_ERROR;
|
||||||
|
} else if (actual_len != tran->cbw.dCBWDataTransferLength) {
|
||||||
|
uerrf("\tMSD: Data phase: wrong actual_len = %d", actual_len);
|
||||||
|
return MSD_TRANSACTIONRESULT_BUS_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* status phase */
|
||||||
|
status = usbhBulkTransfer(&lunp->msdp->epin, &tran->csw,
|
||||||
|
sizeof(tran->csw), &actual_len, MS2ST(1000));
|
||||||
|
|
||||||
|
if (status == USBH_URBSTATUS_CANCELLED) {
|
||||||
|
uerr("\tMSD: Status phase: USBH_URBSTATUS_CANCELLED");
|
||||||
|
return MSD_TRANSACTIONRESULT_DISCONNECTED;
|
||||||
|
} else if (status == USBH_URBSTATUS_STALL) {
|
||||||
|
uerr("\tMSD: Status phase: USBH_URBSTATUS_STALL");
|
||||||
|
return MSD_TRANSACTIONRESULT_STALL;
|
||||||
|
} else if (status != USBH_URBSTATUS_OK) {
|
||||||
|
uerrf("\tMSD: Status phase: status = %d, != OK", status);
|
||||||
|
return MSD_TRANSACTIONRESULT_BUS_ERROR;
|
||||||
|
} else if (actual_len != sizeof(tran->csw)) {
|
||||||
|
uerrf("\tMSD: Status phase: wrong actual_len = %d", actual_len);
|
||||||
|
return MSD_TRANSACTIONRESULT_BUS_ERROR;
|
||||||
|
} else if (tran->csw.dCSWSignature != MSD_CSW_SIGNATURE) {
|
||||||
|
uerr("\tMSD: Status phase: wrong signature");
|
||||||
|
return MSD_TRANSACTIONRESULT_BUS_ERROR;
|
||||||
|
} else if (tran->csw.dCSWTag != lunp->msdp->tag) {
|
||||||
|
uerrf("\tMSD: Status phase: wrong tag (expected %d, got %d)",
|
||||||
|
lunp->msdp->tag, tran->csw.dCSWTag);
|
||||||
|
return MSD_TRANSACTIONRESULT_SYNC_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tran->csw.dCSWDataResidue) {
|
||||||
|
uwarnf("\tMSD: Residue=%d", tran->csw.dCSWDataResidue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return MSD_TRANSACTIONRESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static msd_result_t scsi_inquiry(USBHMassStorageLUNDriver *lunp, scsi_inquiry_response_t *resp) {
|
||||||
|
msd_transaction_t transaction;
|
||||||
|
msd_result_t res;
|
||||||
|
|
||||||
|
_prepare_cbw(&transaction, lunp);
|
||||||
|
transaction.cbw.dCBWDataTransferLength = sizeof(scsi_inquiry_response_t);
|
||||||
|
transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
|
||||||
|
transaction.cbw.bCBWCBLength = 6;
|
||||||
|
transaction.cbw.CBWCB[0] = SCSI_CMD_INQUIRY;
|
||||||
|
transaction.cbw.CBWCB[4] = sizeof(scsi_inquiry_response_t);
|
||||||
|
|
||||||
|
res.tres = _msd_transaction(&transaction, lunp, resp);
|
||||||
|
if (res.tres == MSD_TRANSACTIONRESULT_OK) {
|
||||||
|
res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static msd_result_t scsi_requestsense(USBHMassStorageLUNDriver *lunp, scsi_sense_response_t *resp) {
|
||||||
|
msd_transaction_t transaction;
|
||||||
|
msd_result_t res;
|
||||||
|
|
||||||
|
_prepare_cbw(&transaction, lunp);
|
||||||
|
transaction.cbw.dCBWDataTransferLength = sizeof(scsi_sense_response_t);
|
||||||
|
transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
|
||||||
|
transaction.cbw.bCBWCBLength = 12;
|
||||||
|
transaction.cbw.CBWCB[0] = SCSI_CMD_REQUEST_SENSE;
|
||||||
|
transaction.cbw.CBWCB[4] = sizeof(scsi_sense_response_t);
|
||||||
|
|
||||||
|
res.tres = _msd_transaction(&transaction, lunp, resp);
|
||||||
|
if (res.tres == MSD_TRANSACTIONRESULT_OK) {
|
||||||
|
res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static msd_result_t scsi_testunitready(USBHMassStorageLUNDriver *lunp) {
|
||||||
|
msd_transaction_t transaction;
|
||||||
|
msd_result_t res;
|
||||||
|
|
||||||
|
_prepare_cbw(&transaction, lunp);
|
||||||
|
transaction.cbw.dCBWDataTransferLength = 0;
|
||||||
|
transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
|
||||||
|
transaction.cbw.bCBWCBLength = 6;
|
||||||
|
transaction.cbw.CBWCB[0] = SCSI_CMD_TEST_UNIT_READY;
|
||||||
|
|
||||||
|
res.tres = _msd_transaction(&transaction, lunp, NULL);
|
||||||
|
if (res.tres == MSD_TRANSACTIONRESULT_OK) {
|
||||||
|
res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static msd_result_t scsi_readcapacity10(USBHMassStorageLUNDriver *lunp, scsi_readcapacity10_response_t *resp) {
|
||||||
|
msd_transaction_t transaction;
|
||||||
|
msd_result_t res;
|
||||||
|
|
||||||
|
_prepare_cbw(&transaction, lunp);
|
||||||
|
transaction.cbw.dCBWDataTransferLength = sizeof(scsi_readcapacity10_response_t);
|
||||||
|
transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
|
||||||
|
transaction.cbw.bCBWCBLength = 12;
|
||||||
|
transaction.cbw.CBWCB[0] = SCSI_CMD_READ_CAPACITY_10;
|
||||||
|
|
||||||
|
res.tres = _msd_transaction(&transaction, lunp, resp);
|
||||||
|
if (res.tres == MSD_TRANSACTIONRESULT_OK) {
|
||||||
|
res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static msd_result_t scsi_read10(USBHMassStorageLUNDriver *lunp, uint32_t lba, uint16_t n, uint8_t *data) {
|
||||||
|
msd_transaction_t transaction;
|
||||||
|
msd_result_t res;
|
||||||
|
|
||||||
|
_prepare_cbw(&transaction, lunp);
|
||||||
|
transaction.cbw.dCBWDataTransferLength = n * lunp->info.blk_size;
|
||||||
|
transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
|
||||||
|
transaction.cbw.bCBWCBLength = 10;
|
||||||
|
transaction.cbw.CBWCB[0] = SCSI_CMD_READ_10;
|
||||||
|
transaction.cbw.CBWCB[2] = (uint8_t)(lba >> 24);
|
||||||
|
transaction.cbw.CBWCB[3] = (uint8_t)(lba >> 16);
|
||||||
|
transaction.cbw.CBWCB[4] = (uint8_t)(lba >> 8);
|
||||||
|
transaction.cbw.CBWCB[5] = (uint8_t)(lba);
|
||||||
|
transaction.cbw.CBWCB[7] = (uint8_t)(n >> 8);
|
||||||
|
transaction.cbw.CBWCB[8] = (uint8_t)(n);
|
||||||
|
|
||||||
|
res.tres = _msd_transaction(&transaction, lunp, data);
|
||||||
|
if (res.tres == MSD_TRANSACTIONRESULT_OK) {
|
||||||
|
res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static msd_result_t scsi_write10(USBHMassStorageLUNDriver *lunp, uint32_t lba, uint16_t n, const uint8_t *data) {
|
||||||
|
msd_transaction_t transaction;
|
||||||
|
msd_result_t res;
|
||||||
|
|
||||||
|
_prepare_cbw(&transaction, lunp);
|
||||||
|
transaction.cbw.dCBWDataTransferLength = n * lunp->info.blk_size;
|
||||||
|
transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_H2D;
|
||||||
|
transaction.cbw.bCBWCBLength = 10;
|
||||||
|
transaction.cbw.CBWCB[0] = SCSI_CMD_WRITE_10;
|
||||||
|
transaction.cbw.CBWCB[2] = (uint8_t)(lba >> 24);
|
||||||
|
transaction.cbw.CBWCB[3] = (uint8_t)(lba >> 16);
|
||||||
|
transaction.cbw.CBWCB[4] = (uint8_t)(lba >> 8);
|
||||||
|
transaction.cbw.CBWCB[5] = (uint8_t)(lba);
|
||||||
|
transaction.cbw.CBWCB[7] = (uint8_t)(n >> 8);
|
||||||
|
transaction.cbw.CBWCB[8] = (uint8_t)(n);
|
||||||
|
|
||||||
|
res.tres = _msd_transaction(&transaction, lunp, (uint8_t *)data);
|
||||||
|
if (res.tres == MSD_TRANSACTIONRESULT_OK) {
|
||||||
|
res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Block driver data/functions */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
USBHMassStorageLUNDriver MSBLKD[HAL_USBHMSD_MAX_LUNS];
|
||||||
|
|
||||||
|
static const struct USBHMassStorageDriverVMT blk_vmt = {
|
||||||
|
(bool (*)(void *))usbhmsdLUNIsInserted,
|
||||||
|
(bool (*)(void *))usbhmsdLUNIsProtected,
|
||||||
|
(bool (*)(void *))usbhmsdLUNConnect,
|
||||||
|
(bool (*)(void *))usbhmsdLUNDisconnect,
|
||||||
|
(bool (*)(void *, uint32_t, uint8_t *, uint32_t))usbhmsdLUNRead,
|
||||||
|
(bool (*)(void *, uint32_t, const uint8_t *, uint32_t))usbhmsdLUNWrite,
|
||||||
|
(bool (*)(void *))usbhmsdLUNSync,
|
||||||
|
(bool (*)(void *, BlockDeviceInfo *))usbhmsdLUNGetInfo
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static uint32_t _requestsense(USBHMassStorageLUNDriver *lunp) {
|
||||||
|
scsi_sense_response_t sense;
|
||||||
|
msd_result_t res;
|
||||||
|
|
||||||
|
res = scsi_requestsense(lunp, &sense);
|
||||||
|
if (res.tres != MSD_TRANSACTIONRESULT_OK) {
|
||||||
|
uerr("\tREQUEST SENSE: Transaction error");
|
||||||
|
goto failed;
|
||||||
|
} else if (res.cres == MSD_COMMANDRESULT_FAILED) {
|
||||||
|
uerr("\tREQUEST SENSE: Command Failed");
|
||||||
|
goto failed;
|
||||||
|
} else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
|
||||||
|
//TODO: Do reset, etc.
|
||||||
|
uerr("\tREQUEST SENSE: Command Phase Error");
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
uerrf("\tREQUEST SENSE: Sense key=%x, ASC=%02x, ASCQ=%02x",
|
||||||
|
sense.byte[2] & 0xf, sense.byte[12], sense.byte[13]);
|
||||||
|
|
||||||
|
return (sense.byte[2] & 0xf) | (sense.byte[12] << 8) | (sense.byte[13] << 16);
|
||||||
|
|
||||||
|
failed:
|
||||||
|
return 0xffffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usbhmsdLUNObjectInit(USBHMassStorageLUNDriver *lunp) {
|
||||||
|
osalDbgCheck(lunp != NULL);
|
||||||
|
memset(lunp, 0, sizeof(*lunp));
|
||||||
|
lunp->vmt = &blk_vmt;
|
||||||
|
lunp->state = BLK_STOP;
|
||||||
|
/* Unnecessary because of the memset:
|
||||||
|
lunp->msdp = NULL;
|
||||||
|
lunp->next = NULL;
|
||||||
|
lunp->info.* = 0;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
msd_result_t res;
|
||||||
|
|
||||||
|
osalDbgCheck(msdp != NULL);
|
||||||
|
osalSysLock();
|
||||||
|
//osalDbgAssert((lunp->state == BLK_ACTIVE) || (lunp->state == BLK_READY),
|
||||||
|
// "invalid state");
|
||||||
|
if (lunp->state == BLK_READY) {
|
||||||
|
osalSysUnlock();
|
||||||
|
return HAL_SUCCESS;
|
||||||
|
} else if (lunp->state != BLK_ACTIVE) {
|
||||||
|
osalSysUnlock();
|
||||||
|
return HAL_FAILED;
|
||||||
|
}
|
||||||
|
lunp->state = BLK_CONNECTING;
|
||||||
|
osalSysUnlock();
|
||||||
|
|
||||||
|
osalMutexLock(&msdp->mtx);
|
||||||
|
|
||||||
|
USBH_DEFINE_BUFFER(union {
|
||||||
|
scsi_inquiry_response_t inq;
|
||||||
|
scsi_readcapacity10_response_t cap; }, u);
|
||||||
|
|
||||||
|
uinfo("INQUIRY...");
|
||||||
|
res = scsi_inquiry(lunp, &u.inq);
|
||||||
|
if (res.tres != MSD_TRANSACTIONRESULT_OK) {
|
||||||
|
uerr("\tINQUIRY: Transaction error");
|
||||||
|
goto failed;
|
||||||
|
} else if (res.cres == MSD_COMMANDRESULT_FAILED) {
|
||||||
|
uerr("\tINQUIRY: Command Failed");
|
||||||
|
_requestsense(lunp);
|
||||||
|
goto failed;
|
||||||
|
} else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
|
||||||
|
//TODO: Do reset, etc.
|
||||||
|
uerr("\tINQUIRY: Command Phase Error");
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
uinfof("\tPDT=%02x", u.inq.peripheral & 0x1f);
|
||||||
|
if (u.inq.peripheral != 0) {
|
||||||
|
uerr("\tUnsupported PDT");
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test if unit ready
|
||||||
|
uint8_t i;
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
|
uinfo("TEST UNIT READY...");
|
||||||
|
res = scsi_testunitready(lunp);
|
||||||
|
if (res.tres != MSD_TRANSACTIONRESULT_OK) {
|
||||||
|
uerr("\tTEST UNIT READY: Transaction error");
|
||||||
|
goto failed;
|
||||||
|
} else if (res.cres == MSD_COMMANDRESULT_FAILED) {
|
||||||
|
uerr("\tTEST UNIT READY: Command Failed");
|
||||||
|
_requestsense(lunp);
|
||||||
|
continue;
|
||||||
|
} else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
|
||||||
|
//TODO: Do reset, etc.
|
||||||
|
uerr("\tTEST UNIT READY: Command Phase Error");
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
uinfo("\tReady.");
|
||||||
|
break;
|
||||||
|
// osalThreadSleepMilliseconds(200); // will raise 'code is unreachable' warning
|
||||||
|
}
|
||||||
|
if (i == 10) goto failed;
|
||||||
|
|
||||||
|
// Read capacity
|
||||||
|
uinfo("READ CAPACITY(10)...");
|
||||||
|
res = scsi_readcapacity10(lunp, &u.cap);
|
||||||
|
if (res.tres != MSD_TRANSACTIONRESULT_OK) {
|
||||||
|
uerr("\tREAD CAPACITY(10): Transaction error");
|
||||||
|
goto failed;
|
||||||
|
} else if (res.cres == MSD_COMMANDRESULT_FAILED) {
|
||||||
|
uerr("\tREAD CAPACITY(10): Command Failed");
|
||||||
|
_requestsense(lunp);
|
||||||
|
goto failed;
|
||||||
|
} else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
|
||||||
|
//TODO: Do reset, etc.
|
||||||
|
uerr("\tREAD CAPACITY(10): Command Phase Error");
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
lunp->info.blk_size = __REV(u.cap.block_size);
|
||||||
|
lunp->info.blk_num = __REV(u.cap.last_block_addr) + 1;
|
||||||
|
uinfof("\tBlock size=%dbytes, blocks=%u (~%u MB)", lunp->info.blk_size, lunp->info.blk_num,
|
||||||
|
(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();
|
||||||
|
|
||||||
|
return HAL_SUCCESS;
|
||||||
|
|
||||||
|
/* Connection failed, state reset to BLK_ACTIVE.*/
|
||||||
|
failed:
|
||||||
|
osalMutexUnlock(&msdp->mtx);
|
||||||
|
osalSysLock();
|
||||||
|
lunp->state = BLK_ACTIVE;
|
||||||
|
osalSysUnlock();
|
||||||
|
return HAL_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool usbhmsdLUNDisconnect(USBHMassStorageLUNDriver *lunp) {
|
||||||
|
osalDbgCheck(lunp != NULL);
|
||||||
|
osalSysLock();
|
||||||
|
osalDbgAssert((lunp->state == BLK_ACTIVE) || (lunp->state == BLK_READY),
|
||||||
|
"invalid state");
|
||||||
|
if (lunp->state == BLK_ACTIVE) {
|
||||||
|
osalSysUnlock();
|
||||||
|
return HAL_SUCCESS;
|
||||||
|
}
|
||||||
|
lunp->state = BLK_DISCONNECTING;
|
||||||
|
osalSysUnlock();
|
||||||
|
|
||||||
|
//TODO: complete
|
||||||
|
|
||||||
|
osalSysLock();
|
||||||
|
lunp->state = BLK_ACTIVE;
|
||||||
|
osalSysUnlock();
|
||||||
|
return HAL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool usbhmsdLUNRead(USBHMassStorageLUNDriver *lunp, uint32_t startblk,
|
||||||
|
uint8_t *buffer, uint32_t n) {
|
||||||
|
|
||||||
|
osalDbgCheck(lunp != NULL);
|
||||||
|
bool ret = HAL_FAILED;
|
||||||
|
uint16_t blocks;
|
||||||
|
msd_result_t res;
|
||||||
|
|
||||||
|
osalSysLock();
|
||||||
|
if (lunp->state != BLK_READY) {
|
||||||
|
osalSysUnlock();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
lunp->state = BLK_READING;
|
||||||
|
osalSysUnlock();
|
||||||
|
|
||||||
|
osalMutexLock(&lunp->msdp->mtx);
|
||||||
|
while (n) {
|
||||||
|
if (n > 0xffff) {
|
||||||
|
blocks = 0xffff;
|
||||||
|
} else {
|
||||||
|
blocks = (uint16_t)n;
|
||||||
|
}
|
||||||
|
res = scsi_read10(lunp, startblk, blocks, buffer);
|
||||||
|
if (res.tres != MSD_TRANSACTIONRESULT_OK) {
|
||||||
|
uerr("\tREAD (10): Transaction error");
|
||||||
|
goto exit;
|
||||||
|
} else if (res.cres == MSD_COMMANDRESULT_FAILED) {
|
||||||
|
//TODO: request sense, and act appropriately
|
||||||
|
uerr("\tREAD (10): Command Failed");
|
||||||
|
_requestsense(lunp);
|
||||||
|
goto exit;
|
||||||
|
} else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
|
||||||
|
//TODO: Do reset, etc.
|
||||||
|
uerr("\tREAD (10): Command Phase Error");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
n -= blocks;
|
||||||
|
startblk += blocks;
|
||||||
|
buffer += blocks * lunp->info.blk_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool usbhmsdLUNWrite(USBHMassStorageLUNDriver *lunp, uint32_t startblk,
|
||||||
|
const uint8_t *buffer, uint32_t n) {
|
||||||
|
|
||||||
|
osalDbgCheck(lunp != NULL);
|
||||||
|
bool ret = HAL_FAILED;
|
||||||
|
uint16_t blocks;
|
||||||
|
msd_result_t res;
|
||||||
|
|
||||||
|
osalSysLock();
|
||||||
|
if (lunp->state != BLK_READY) {
|
||||||
|
osalSysUnlock();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
lunp->state = BLK_WRITING;
|
||||||
|
osalSysUnlock();
|
||||||
|
|
||||||
|
osalMutexLock(&lunp->msdp->mtx);
|
||||||
|
while (n) {
|
||||||
|
if (n > 0xffff) {
|
||||||
|
blocks = 0xffff;
|
||||||
|
} else {
|
||||||
|
blocks = (uint16_t)n;
|
||||||
|
}
|
||||||
|
res = scsi_write10(lunp, startblk, blocks, buffer);
|
||||||
|
if (res.tres != MSD_TRANSACTIONRESULT_OK) {
|
||||||
|
uerr("\tWRITE (10): Transaction error");
|
||||||
|
goto exit;
|
||||||
|
} else if (res.cres == MSD_COMMANDRESULT_FAILED) {
|
||||||
|
//TODO: request sense, and act appropriately
|
||||||
|
uerr("\tWRITE (10): Command Failed");
|
||||||
|
_requestsense(lunp);
|
||||||
|
goto exit;
|
||||||
|
} else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
|
||||||
|
//TODO: Do reset, etc.
|
||||||
|
uerr("\tWRITE (10): Command Phase Error");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
n -= blocks;
|
||||||
|
startblk += blocks;
|
||||||
|
buffer += blocks * lunp->info.blk_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool usbhmsdLUNSync(USBHMassStorageLUNDriver *lunp) {
|
||||||
|
osalDbgCheck(lunp != NULL);
|
||||||
|
(void)lunp;
|
||||||
|
//TODO: Do SCSI Sync
|
||||||
|
return HAL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool usbhmsdLUNGetInfo(USBHMassStorageLUNDriver *lunp, BlockDeviceInfo *bdip) {
|
||||||
|
osalDbgCheck(lunp != NULL);
|
||||||
|
osalDbgCheck(bdip != NULL);
|
||||||
|
*bdip = lunp->info;
|
||||||
|
return HAL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool usbhmsdLUNIsInserted(USBHMassStorageLUNDriver *lunp) {
|
||||||
|
osalDbgCheck(lunp != NULL);
|
||||||
|
blkstate_t state;
|
||||||
|
osalSysLock();
|
||||||
|
state = lunp->state;
|
||||||
|
osalSysUnlock();
|
||||||
|
return (state >= BLK_ACTIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool usbhmsdLUNIsProtected(USBHMassStorageLUNDriver *lunp) {
|
||||||
|
osalDbgCheck(lunp != NULL);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usbhmsdObjectInit(USBHMassStorageDriver *msdp) {
|
||||||
|
osalDbgCheck(msdp != NULL);
|
||||||
|
memset(msdp, 0, sizeof(*msdp));
|
||||||
|
msdp->info = &usbhmsdClassDriverInfo;
|
||||||
|
osalMutexObjectInit(&msdp->mtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||||
|
Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hal.h"
|
||||||
|
#include "usbh.h"
|
||||||
|
|
||||||
|
#if HAL_USBH_USE_UVC
|
||||||
|
|
||||||
|
#if !HAL_USE_USBH
|
||||||
|
#error "USBHUVC needs HAL_USE_USBH"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !HAL_USBH_USE_IAD
|
||||||
|
#error "USBHUVC needs HAL_USBH_USE_IAD"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USBHUVC_DEBUG_ENABLE_TRACE
|
||||||
|
#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
|
||||||
|
#define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define udbgf(f, ...) do {} while(0)
|
||||||
|
#define udbg(f, ...) do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USBHUVC_DEBUG_ENABLE_INFO
|
||||||
|
#define uinfof(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
|
||||||
|
#define uinfo(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define uinfof(f, ...) do {} while(0)
|
||||||
|
#define uinfo(f, ...) do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USBHUVC_DEBUG_ENABLE_WARNINGS
|
||||||
|
#define uwarnf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
|
||||||
|
#define uwarn(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define uwarnf(f, ...) do {} while(0)
|
||||||
|
#define uwarn(f, ...) do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USBHUVC_DEBUG_ENABLE_ERRORS
|
||||||
|
#define uerrf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
|
||||||
|
#define uerr(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define uerrf(f, ...) do {} while(0)
|
||||||
|
#define uerr(f, ...) do {} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
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 const usbh_classdriver_vmt_t class_driver_vmt = {
|
||||||
|
uvc_load,
|
||||||
|
uvc_unload
|
||||||
|
};
|
||||||
|
const usbh_classdriverinfo_t usbhuvcClassDriverInfo = {
|
||||||
|
0x0e, 0x03, 0x00, "UVC", &class_driver_vmt
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static usbh_baseclassdriver_t *uvc_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem) {
|
||||||
|
(void)dev;
|
||||||
|
(void)descriptor;
|
||||||
|
(void)rem;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uvc_unload(usbh_baseclassdriver_t *drv) {
|
||||||
|
(void)drv;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,220 @@
|
||||||
|
##############################################################################
|
||||||
|
# Build global options
|
||||||
|
# NOTE: Can be overridden externally.
|
||||||
|
#
|
||||||
|
|
||||||
|
# Compiler options here.
|
||||||
|
ifeq ($(USE_OPT),)
|
||||||
|
USE_OPT = -Os -ggdb -fomit-frame-pointer -falign-functions=16
|
||||||
|
endif
|
||||||
|
|
||||||
|
# C specific options here (added to USE_OPT).
|
||||||
|
ifeq ($(USE_COPT),)
|
||||||
|
USE_COPT =
|
||||||
|
endif
|
||||||
|
|
||||||
|
# C++ specific options here (added to USE_OPT).
|
||||||
|
ifeq ($(USE_CPPOPT),)
|
||||||
|
USE_CPPOPT = -fno-rtti
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Enable this if you want the linker to remove unused code and data
|
||||||
|
ifeq ($(USE_LINK_GC),)
|
||||||
|
USE_LINK_GC = yes
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Linker extra options here.
|
||||||
|
ifeq ($(USE_LDOPT),)
|
||||||
|
USE_LDOPT =
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Enable this if you want link time optimizations (LTO)
|
||||||
|
ifeq ($(USE_LTO),)
|
||||||
|
USE_LTO = yes
|
||||||
|
endif
|
||||||
|
|
||||||
|
# If enabled, this option allows to compile the application in THUMB mode.
|
||||||
|
ifeq ($(USE_THUMB),)
|
||||||
|
USE_THUMB = yes
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Enable this if you want to see the full log while compiling.
|
||||||
|
ifeq ($(USE_VERBOSE_COMPILE),)
|
||||||
|
USE_VERBOSE_COMPILE = no
|
||||||
|
endif
|
||||||
|
|
||||||
|
# If enabled, this option makes the build process faster by not compiling
|
||||||
|
# modules not used in the current configuration.
|
||||||
|
ifeq ($(USE_SMART_BUILD),)
|
||||||
|
USE_SMART_BUILD = no
|
||||||
|
endif
|
||||||
|
|
||||||
|
#
|
||||||
|
# Build global options
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Architecture or project specific options
|
||||||
|
#
|
||||||
|
|
||||||
|
# Stack size to be allocated to the Cortex-M process stack. This stack is
|
||||||
|
# the stack used by the main() thread.
|
||||||
|
ifeq ($(USE_PROCESS_STACKSIZE),)
|
||||||
|
USE_PROCESS_STACKSIZE = 0x800
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Stack size to the allocated to the Cortex-M main/exceptions stack. This
|
||||||
|
# stack is used for processing interrupts and exceptions.
|
||||||
|
ifeq ($(USE_EXCEPTIONS_STACKSIZE),)
|
||||||
|
USE_EXCEPTIONS_STACKSIZE = 0x800
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Enables the use of FPU on Cortex-M4 (no, softfp, hard).
|
||||||
|
ifeq ($(USE_FPU),)
|
||||||
|
USE_FPU = no
|
||||||
|
endif
|
||||||
|
|
||||||
|
#
|
||||||
|
# Architecture or project specific options
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Project, sources and paths
|
||||||
|
#
|
||||||
|
|
||||||
|
# Define project name here
|
||||||
|
PROJECT = ch
|
||||||
|
|
||||||
|
# Imported source files and paths
|
||||||
|
CHIBIOS = ../../../../../ChibiOS-RT
|
||||||
|
CHIBIOS_CONTRIB = $(CHIBIOS)/../ChibiOS-Contrib
|
||||||
|
# Startup files.
|
||||||
|
include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/startup_stm32f4xx.mk
|
||||||
|
# HAL-OSAL files (optional).
|
||||||
|
include $(CHIBIOS_CONTRIB)/os/hal/hal.mk
|
||||||
|
include $(CHIBIOS_CONTRIB)/os/hal/ports/STM32/STM32F4xx/platform.mk
|
||||||
|
include $(CHIBIOS)/os/hal/boards/ST_STM32F4_DISCOVERY/board.mk
|
||||||
|
include $(CHIBIOS)/os/hal/osal/rt/osal.mk
|
||||||
|
# RTOS files (optional).
|
||||||
|
include $(CHIBIOS)/os/rt/rt.mk
|
||||||
|
include $(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk
|
||||||
|
# Other files (optional).
|
||||||
|
include $(CHIBIOS)/test/rt/test.mk
|
||||||
|
|
||||||
|
# Define linker script file here
|
||||||
|
LDSCRIPT= $(STARTUPLD)/STM32F407xG.ld
|
||||||
|
|
||||||
|
# C sources that can be compiled in ARM or THUMB mode depending on the global
|
||||||
|
# setting.
|
||||||
|
CSRC = $(STARTUPSRC) \
|
||||||
|
$(KERNSRC) \
|
||||||
|
$(PORTSRC) \
|
||||||
|
$(OSALSRC) \
|
||||||
|
$(HALSRC) \
|
||||||
|
$(PLATFORMSRC) \
|
||||||
|
$(BOARDSRC) \
|
||||||
|
$(TESTSRC) \
|
||||||
|
$(CHIBIOS)/os/various/shell.c \
|
||||||
|
$(CHIBIOS)/os/hal/lib/streams/memstreams.c \
|
||||||
|
$(CHIBIOS)/os/hal/lib/streams/chprintf.c \
|
||||||
|
ff.c fatfs_diskio.c main.c
|
||||||
|
|
||||||
|
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
|
||||||
|
# setting.
|
||||||
|
CPPSRC =
|
||||||
|
|
||||||
|
# C sources to be compiled in ARM mode regardless of the global setting.
|
||||||
|
# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
|
||||||
|
# option that results in lower performance and larger code size.
|
||||||
|
ACSRC =
|
||||||
|
|
||||||
|
# C++ sources to be compiled in ARM mode regardless of the global setting.
|
||||||
|
# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
|
||||||
|
# option that results in lower performance and larger code size.
|
||||||
|
ACPPSRC =
|
||||||
|
|
||||||
|
# C sources to be compiled in THUMB mode regardless of the global setting.
|
||||||
|
# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
|
||||||
|
# option that results in lower performance and larger code size.
|
||||||
|
TCSRC =
|
||||||
|
|
||||||
|
# C sources to be compiled in THUMB mode regardless of the global setting.
|
||||||
|
# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
|
||||||
|
# option that results in lower performance and larger code size.
|
||||||
|
TCPPSRC =
|
||||||
|
|
||||||
|
# List ASM source files here
|
||||||
|
ASMSRC = $(STARTUPASM) $(PORTASM) $(OSALASM)
|
||||||
|
|
||||||
|
INCDIR = $(STARTUPINC) $(KERNINC) $(PORTINC) $(OSALINC) \
|
||||||
|
$(HALINC) $(PLATFORMINC) $(BOARDINC) $(TESTINC) \
|
||||||
|
$(CHIBIOS)/os/hal/lib/streams $(CHIBIOS)/os/various
|
||||||
|
|
||||||
|
#
|
||||||
|
# Project, sources and paths
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Compiler settings
|
||||||
|
#
|
||||||
|
|
||||||
|
MCU = cortex-m4
|
||||||
|
|
||||||
|
#TRGT = arm-elf-
|
||||||
|
TRGT = arm-none-eabi-
|
||||||
|
CC = $(TRGT)gcc
|
||||||
|
CPPC = $(TRGT)g++
|
||||||
|
# Enable loading with g++ only if you need C++ runtime support.
|
||||||
|
# NOTE: You can use C++ even without C++ support if you are careful. C++
|
||||||
|
# runtime support makes code size explode.
|
||||||
|
LD = $(TRGT)gcc
|
||||||
|
#LD = $(TRGT)g++
|
||||||
|
CP = $(TRGT)objcopy
|
||||||
|
AS = $(TRGT)gcc -x assembler-with-cpp
|
||||||
|
AR = $(TRGT)ar
|
||||||
|
OD = $(TRGT)objdump
|
||||||
|
SZ = $(TRGT)size
|
||||||
|
HEX = $(CP) -O ihex
|
||||||
|
BIN = $(CP) -O binary
|
||||||
|
|
||||||
|
# ARM-specific options here
|
||||||
|
AOPT =
|
||||||
|
|
||||||
|
# THUMB-specific options here
|
||||||
|
TOPT = -mthumb -DTHUMB
|
||||||
|
|
||||||
|
# Define C warning options here
|
||||||
|
CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes
|
||||||
|
|
||||||
|
# Define C++ warning options here
|
||||||
|
CPPWARN = -Wall -Wextra -Wundef
|
||||||
|
|
||||||
|
#
|
||||||
|
# Compiler settings
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Start of user section
|
||||||
|
#
|
||||||
|
|
||||||
|
# List all user C define here, like -D_DEBUG=1
|
||||||
|
UDEFS =
|
||||||
|
|
||||||
|
# Define ASM defines here
|
||||||
|
UADEFS =
|
||||||
|
|
||||||
|
# List all user directories here
|
||||||
|
UINCDIR =
|
||||||
|
|
||||||
|
# List the user directory to look for the libraries here
|
||||||
|
ULIBDIR =
|
||||||
|
|
||||||
|
# List all user libraries here
|
||||||
|
ULIBS =
|
||||||
|
|
||||||
|
#
|
||||||
|
# End of user defines
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
RULESPATH = $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC
|
||||||
|
include $(RULESPATH)/rules.mk
|
|
@ -0,0 +1,501 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file templates/chconf.h
|
||||||
|
* @brief Configuration file template.
|
||||||
|
* @details A copy of this file must be placed in each project directory, it
|
||||||
|
* contains the application specific kernel settings.
|
||||||
|
*
|
||||||
|
* @addtogroup config
|
||||||
|
* @details Kernel related settings and hooks.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CHCONF_H_
|
||||||
|
#define _CHCONF_H_
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/**
|
||||||
|
* @name System timers settings
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief System time counter resolution.
|
||||||
|
* @note Allowed values are 16 or 32 bits.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_ST_RESOLUTION 32
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief System tick frequency.
|
||||||
|
* @details Frequency of the system timer that drives the system ticks. This
|
||||||
|
* setting also defines the system tick time unit.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_ST_FREQUENCY 1000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Time delta constant for the tick-less mode.
|
||||||
|
* @note If this value is zero then the system uses the classic
|
||||||
|
* periodic tick. This value represents the minimum number
|
||||||
|
* of ticks that is safe to specify in a timeout directive.
|
||||||
|
* The value one is not valid, timeouts are rounded up to
|
||||||
|
* this value.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_ST_TIMEDELTA 0
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/**
|
||||||
|
* @name Kernel parameters and options
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Round robin interval.
|
||||||
|
* @details This constant is the number of system ticks allowed for the
|
||||||
|
* threads before preemption occurs. Setting this value to zero
|
||||||
|
* disables the preemption for threads with equal priority and the
|
||||||
|
* round robin becomes cooperative. Note that higher priority
|
||||||
|
* threads can still preempt, the kernel is always preemptive.
|
||||||
|
* @note Disabling the round robin preemption makes the kernel more compact
|
||||||
|
* and generally faster.
|
||||||
|
* @note The round robin preemption is not supported in tickless mode and
|
||||||
|
* must be set to zero in that case.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_TIME_QUANTUM 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Managed RAM size.
|
||||||
|
* @details Size of the RAM area to be managed by the OS. If set to zero
|
||||||
|
* then the whole available RAM is used. The core memory is made
|
||||||
|
* available to the heap allocator and/or can be used directly through
|
||||||
|
* the simplified core memory allocator.
|
||||||
|
*
|
||||||
|
* @note In order to let the OS manage the whole RAM the linker script must
|
||||||
|
* provide the @p __heap_base__ and @p __heap_end__ symbols.
|
||||||
|
* @note Requires @p CH_CFG_USE_MEMCORE.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_MEMCORE_SIZE 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Idle thread automatic spawn suppression.
|
||||||
|
* @details When this option is activated the function @p chSysInit()
|
||||||
|
* does not spawn the idle thread. The application @p main()
|
||||||
|
* function becomes the idle thread and must implement an
|
||||||
|
* infinite loop.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_NO_IDLE_THREAD FALSE
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/**
|
||||||
|
* @name Performance options
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief OS optimization.
|
||||||
|
* @details If enabled then time efficient rather than space efficient code
|
||||||
|
* is used when two possible implementations exist.
|
||||||
|
*
|
||||||
|
* @note This is not related to the compiler optimization options.
|
||||||
|
* @note The default is @p TRUE.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_OPTIMIZE_SPEED TRUE
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/**
|
||||||
|
* @name Subsystem options
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Time Measurement APIs.
|
||||||
|
* @details If enabled then the time measurement APIs are included in
|
||||||
|
* the kernel.
|
||||||
|
*
|
||||||
|
* @note The default is @p TRUE.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_USE_TM TRUE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Threads registry APIs.
|
||||||
|
* @details If enabled then the registry APIs are included in the kernel.
|
||||||
|
*
|
||||||
|
* @note The default is @p TRUE.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_USE_REGISTRY TRUE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Threads synchronization APIs.
|
||||||
|
* @details If enabled then the @p chThdWait() function is included in
|
||||||
|
* the kernel.
|
||||||
|
*
|
||||||
|
* @note The default is @p TRUE.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_USE_WAITEXIT TRUE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Semaphores APIs.
|
||||||
|
* @details If enabled then the Semaphores APIs are included in the kernel.
|
||||||
|
*
|
||||||
|
* @note The default is @p TRUE.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_USE_SEMAPHORES TRUE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Semaphores queuing mode.
|
||||||
|
* @details If enabled then the threads are enqueued on semaphores by
|
||||||
|
* priority rather than in FIFO order.
|
||||||
|
*
|
||||||
|
* @note The default is @p FALSE. Enable this if you have special
|
||||||
|
* requirements.
|
||||||
|
* @note Requires @p CH_CFG_USE_SEMAPHORES.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_USE_SEMAPHORES_PRIORITY FALSE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mutexes APIs.
|
||||||
|
* @details If enabled then the mutexes APIs are included in the kernel.
|
||||||
|
*
|
||||||
|
* @note The default is @p TRUE.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_USE_MUTEXES TRUE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables recursive behavior on mutexes.
|
||||||
|
* @note Recursive mutexes are heavier and have an increased
|
||||||
|
* memory footprint.
|
||||||
|
*
|
||||||
|
* @note The default is @p FALSE.
|
||||||
|
* @note Requires @p CH_CFG_USE_MUTEXES.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_USE_MUTEXES_RECURSIVE FALSE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Conditional Variables APIs.
|
||||||
|
* @details If enabled then the conditional variables APIs are included
|
||||||
|
* in the kernel.
|
||||||
|
*
|
||||||
|
* @note The default is @p TRUE.
|
||||||
|
* @note Requires @p CH_CFG_USE_MUTEXES.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_USE_CONDVARS TRUE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Conditional Variables APIs with timeout.
|
||||||
|
* @details If enabled then the conditional variables APIs with timeout
|
||||||
|
* specification are included in the kernel.
|
||||||
|
*
|
||||||
|
* @note The default is @p TRUE.
|
||||||
|
* @note Requires @p CH_CFG_USE_CONDVARS.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_USE_CONDVARS_TIMEOUT TRUE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Events Flags APIs.
|
||||||
|
* @details If enabled then the event flags APIs are included in the kernel.
|
||||||
|
*
|
||||||
|
* @note The default is @p TRUE.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_USE_EVENTS TRUE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Events Flags APIs with timeout.
|
||||||
|
* @details If enabled then the events APIs with timeout specification
|
||||||
|
* are included in the kernel.
|
||||||
|
*
|
||||||
|
* @note The default is @p TRUE.
|
||||||
|
* @note Requires @p CH_CFG_USE_EVENTS.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_USE_EVENTS_TIMEOUT TRUE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Synchronous Messages APIs.
|
||||||
|
* @details If enabled then the synchronous messages APIs are included
|
||||||
|
* in the kernel.
|
||||||
|
*
|
||||||
|
* @note The default is @p TRUE.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_USE_MESSAGES TRUE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Synchronous Messages queuing mode.
|
||||||
|
* @details If enabled then messages are served by priority rather than in
|
||||||
|
* FIFO order.
|
||||||
|
*
|
||||||
|
* @note The default is @p FALSE. Enable this if you have special
|
||||||
|
* requirements.
|
||||||
|
* @note Requires @p CH_CFG_USE_MESSAGES.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_USE_MESSAGES_PRIORITY FALSE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mailboxes APIs.
|
||||||
|
* @details If enabled then the asynchronous messages (mailboxes) APIs are
|
||||||
|
* included in the kernel.
|
||||||
|
*
|
||||||
|
* @note The default is @p TRUE.
|
||||||
|
* @note Requires @p CH_CFG_USE_SEMAPHORES.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_USE_MAILBOXES TRUE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief I/O Queues APIs.
|
||||||
|
* @details If enabled then the I/O queues APIs are included in the kernel.
|
||||||
|
*
|
||||||
|
* @note The default is @p TRUE.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_USE_QUEUES TRUE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Core Memory Manager APIs.
|
||||||
|
* @details If enabled then the core memory manager APIs are included
|
||||||
|
* in the kernel.
|
||||||
|
*
|
||||||
|
* @note The default is @p TRUE.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_USE_MEMCORE TRUE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Heap Allocator APIs.
|
||||||
|
* @details If enabled then the memory heap allocator APIs are included
|
||||||
|
* in the kernel.
|
||||||
|
*
|
||||||
|
* @note The default is @p TRUE.
|
||||||
|
* @note Requires @p CH_CFG_USE_MEMCORE and either @p CH_CFG_USE_MUTEXES or
|
||||||
|
* @p CH_CFG_USE_SEMAPHORES.
|
||||||
|
* @note Mutexes are recommended.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_USE_HEAP TRUE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Memory Pools Allocator APIs.
|
||||||
|
* @details If enabled then the memory pools allocator APIs are included
|
||||||
|
* in the kernel.
|
||||||
|
*
|
||||||
|
* @note The default is @p TRUE.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_USE_MEMPOOLS TRUE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Dynamic Threads APIs.
|
||||||
|
* @details If enabled then the dynamic threads creation APIs are included
|
||||||
|
* in the kernel.
|
||||||
|
*
|
||||||
|
* @note The default is @p TRUE.
|
||||||
|
* @note Requires @p CH_CFG_USE_WAITEXIT.
|
||||||
|
* @note Requires @p CH_CFG_USE_HEAP and/or @p CH_CFG_USE_MEMPOOLS.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_USE_DYNAMIC TRUE
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/**
|
||||||
|
* @name Debug options
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Debug option, kernel statistics.
|
||||||
|
*
|
||||||
|
* @note The default is @p FALSE.
|
||||||
|
*/
|
||||||
|
#define CH_DBG_STATISTICS FALSE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Debug option, system state check.
|
||||||
|
* @details If enabled the correct call protocol for system APIs is checked
|
||||||
|
* at runtime.
|
||||||
|
*
|
||||||
|
* @note The default is @p FALSE.
|
||||||
|
*/
|
||||||
|
#define CH_DBG_SYSTEM_STATE_CHECK TRUE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Debug option, parameters checks.
|
||||||
|
* @details If enabled then the checks on the API functions input
|
||||||
|
* parameters are activated.
|
||||||
|
*
|
||||||
|
* @note The default is @p FALSE.
|
||||||
|
*/
|
||||||
|
#define CH_DBG_ENABLE_CHECKS TRUE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Debug option, consistency checks.
|
||||||
|
* @details If enabled then all the assertions in the kernel code are
|
||||||
|
* activated. This includes consistency checks inside the kernel,
|
||||||
|
* runtime anomalies and port-defined checks.
|
||||||
|
*
|
||||||
|
* @note The default is @p FALSE.
|
||||||
|
*/
|
||||||
|
#define CH_DBG_ENABLE_ASSERTS TRUE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Debug option, trace buffer.
|
||||||
|
* @details If enabled then the context switch circular trace buffer is
|
||||||
|
* activated.
|
||||||
|
*
|
||||||
|
* @note The default is @p FALSE.
|
||||||
|
*/
|
||||||
|
#define CH_DBG_ENABLE_TRACE FALSE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Debug option, stack checks.
|
||||||
|
* @details If enabled then a runtime stack check is performed.
|
||||||
|
*
|
||||||
|
* @note The default is @p FALSE.
|
||||||
|
* @note The stack check is performed in a architecture/port dependent way.
|
||||||
|
* It may not be implemented or some ports.
|
||||||
|
* @note The default failure mode is to halt the system with the global
|
||||||
|
* @p panic_msg variable set to @p NULL.
|
||||||
|
*/
|
||||||
|
#define CH_DBG_ENABLE_STACK_CHECK TRUE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Debug option, stacks initialization.
|
||||||
|
* @details If enabled then the threads working area is filled with a byte
|
||||||
|
* value when a thread is created. This can be useful for the
|
||||||
|
* runtime measurement of the used stack.
|
||||||
|
*
|
||||||
|
* @note The default is @p FALSE.
|
||||||
|
*/
|
||||||
|
#define CH_DBG_FILL_THREADS TRUE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Debug option, threads profiling.
|
||||||
|
* @details If enabled then a field is added to the @p thread_t structure that
|
||||||
|
* counts the system ticks occurred while executing the thread.
|
||||||
|
*
|
||||||
|
* @note The default is @p FALSE.
|
||||||
|
* @note This debug option is not currently compatible with the
|
||||||
|
* tickless mode.
|
||||||
|
*/
|
||||||
|
#define CH_DBG_THREADS_PROFILING FALSE
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/**
|
||||||
|
* @name Kernel hooks
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Threads descriptor structure extension.
|
||||||
|
* @details User fields added to the end of the @p thread_t structure.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_THREAD_EXTRA_FIELDS \
|
||||||
|
/* Add threads custom fields here.*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Threads initialization hook.
|
||||||
|
* @details User initialization code added to the @p chThdInit() API.
|
||||||
|
*
|
||||||
|
* @note It is invoked from within @p chThdInit() and implicitly from all
|
||||||
|
* the threads creation APIs.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_THREAD_INIT_HOOK(tp) { \
|
||||||
|
/* Add threads initialization code here.*/ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Threads finalization hook.
|
||||||
|
* @details User finalization code added to the @p chThdExit() API.
|
||||||
|
*
|
||||||
|
* @note It is inserted into lock zone.
|
||||||
|
* @note It is also invoked when the threads simply return in order to
|
||||||
|
* terminate.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_THREAD_EXIT_HOOK(tp) { \
|
||||||
|
/* Add threads finalization code here.*/ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Context switch hook.
|
||||||
|
* @details This hook is invoked just before switching between threads.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp) { \
|
||||||
|
/* Context switch code here.*/ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Idle thread enter hook.
|
||||||
|
* @note This hook is invoked within a critical zone, no OS functions
|
||||||
|
* should be invoked from here.
|
||||||
|
* @note This macro can be used to activate a power saving mode.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_IDLE_ENTER_HOOK() { \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Idle thread leave hook.
|
||||||
|
* @note This hook is invoked within a critical zone, no OS functions
|
||||||
|
* should be invoked from here.
|
||||||
|
* @note This macro can be used to deactivate a power saving mode.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_IDLE_LEAVE_HOOK() { \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Idle Loop hook.
|
||||||
|
* @details This hook is continuously invoked by the idle thread loop.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_IDLE_LOOP_HOOK() { \
|
||||||
|
/* Idle loop code here.*/ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief System tick event hook.
|
||||||
|
* @details This hook is invoked in the system tick handler immediately
|
||||||
|
* after processing the virtual timers queue.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_SYSTEM_TICK_HOOK() { \
|
||||||
|
/* System tick event code here.*/ \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief System halt hook.
|
||||||
|
* @details This hook is invoked in case to a system halting error before
|
||||||
|
* the system is halted.
|
||||||
|
*/
|
||||||
|
#define CH_CFG_SYSTEM_HALT_HOOK(reason) { \
|
||||||
|
/* System halt code here.*/ \
|
||||||
|
void usbDbgSystemHalted(void); \
|
||||||
|
usbDbgSystemHalted(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Port-specific settings (override port settings defaulted in chcore.h). */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
#endif /* _CHCONF_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*-----------------------------------------------------------------------/
|
||||||
|
/ Low level disk interface modlue include file (C)ChaN, 2014 /
|
||||||
|
/-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef _DISKIO_DEFINED
|
||||||
|
#define _DISKIO_DEFINED
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _USE_WRITE 1 /* 1: Enable disk_write function */
|
||||||
|
#define _USE_IOCTL 1 /* 1: Enable disk_ioctl fucntion */
|
||||||
|
|
||||||
|
#include "integer.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* Status of Disk Functions */
|
||||||
|
typedef BYTE DSTATUS;
|
||||||
|
|
||||||
|
/* Results of Disk Functions */
|
||||||
|
typedef enum {
|
||||||
|
RES_OK = 0, /* 0: Successful */
|
||||||
|
RES_ERROR, /* 1: R/W Error */
|
||||||
|
RES_WRPRT, /* 2: Write Protected */
|
||||||
|
RES_NOTRDY, /* 3: Not Ready */
|
||||||
|
RES_PARERR /* 4: Invalid Parameter */
|
||||||
|
} DRESULT;
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------*/
|
||||||
|
/* Prototypes for disk control functions */
|
||||||
|
|
||||||
|
|
||||||
|
DSTATUS disk_initialize (BYTE pdrv);
|
||||||
|
DSTATUS disk_status (BYTE pdrv);
|
||||||
|
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
|
||||||
|
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
|
||||||
|
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
|
||||||
|
|
||||||
|
|
||||||
|
/* Disk Status Bits (DSTATUS) */
|
||||||
|
|
||||||
|
#define STA_NOINIT 0x01 /* Drive not initialized */
|
||||||
|
#define STA_NODISK 0x02 /* No medium in the drive */
|
||||||
|
#define STA_PROTECT 0x04 /* Write protected */
|
||||||
|
|
||||||
|
|
||||||
|
/* Command code for disk_ioctrl fucntion */
|
||||||
|
|
||||||
|
/* Generic command (Used by FatFs) */
|
||||||
|
#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */
|
||||||
|
#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */
|
||||||
|
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */
|
||||||
|
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */
|
||||||
|
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */
|
||||||
|
|
||||||
|
/* Generic command (Not used by FatFs) */
|
||||||
|
#define CTRL_POWER 5 /* Get/Set power status */
|
||||||
|
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
|
||||||
|
#define CTRL_EJECT 7 /* Eject media */
|
||||||
|
#define CTRL_FORMAT 8 /* Create physical format on the media */
|
||||||
|
|
||||||
|
/* MMC/SDC specific ioctl command */
|
||||||
|
#define MMC_GET_TYPE 10 /* Get card type */
|
||||||
|
#define MMC_GET_CSD 11 /* Get CSD */
|
||||||
|
#define MMC_GET_CID 12 /* Get CID */
|
||||||
|
#define MMC_GET_OCR 13 /* Get OCR */
|
||||||
|
#define MMC_GET_SDSTAT 14 /* Get SD status */
|
||||||
|
|
||||||
|
/* ATA/CF specific ioctl command */
|
||||||
|
#define ATA_GET_REV 20 /* Get F/W revision */
|
||||||
|
#define ATA_GET_MODEL 21 /* Get model name */
|
||||||
|
#define ATA_GET_SN 22 /* Get serial number */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,144 @@
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2007 */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* This is a stub disk I/O module that acts as front end of the existing */
|
||||||
|
/* disk I/O modules and attach it to FatFs module with common interface. */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "hal.h"
|
||||||
|
#include "ffconf.h"
|
||||||
|
#include "diskio.h"
|
||||||
|
|
||||||
|
#include "usbh.h"
|
||||||
|
#include "usbh/dev/msd.h"
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Correspondence between physical drive number and physical drive. */
|
||||||
|
#define MSDLUN0 0
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Inidialize a Drive */
|
||||||
|
|
||||||
|
DSTATUS disk_initialize (
|
||||||
|
BYTE pdrv /* Physical drive nmuber (0..) */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DSTATUS stat;
|
||||||
|
|
||||||
|
switch (pdrv) {
|
||||||
|
case MSDLUN0:
|
||||||
|
stat = 0;
|
||||||
|
/* It is initialized externally, just reads the status.*/
|
||||||
|
if (blkGetDriverState(&MSBLKD[0]) != BLK_READY)
|
||||||
|
stat |= STA_NOINIT;
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
return STA_NOINIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Return Disk Status */
|
||||||
|
|
||||||
|
DSTATUS disk_status (
|
||||||
|
BYTE pdrv /* Physical drive nmuber (0..) */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DSTATUS stat;
|
||||||
|
|
||||||
|
switch (pdrv) {
|
||||||
|
case MSDLUN0:
|
||||||
|
stat = 0;
|
||||||
|
/* It is initialized externally, just reads the status.*/
|
||||||
|
if (blkGetDriverState(&MSBLKD[0]) != BLK_READY)
|
||||||
|
stat |= STA_NOINIT;
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
return STA_NOINIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Read Sector(s) */
|
||||||
|
|
||||||
|
DRESULT disk_read (
|
||||||
|
BYTE pdrv, /* Physical drive nmuber (0..) */
|
||||||
|
BYTE *buff, /* Data buffer to store read data */
|
||||||
|
DWORD sector, /* Sector address (LBA) */
|
||||||
|
UINT count /* Number of sectors to read (1..255) */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
switch (pdrv) {
|
||||||
|
case MSDLUN0:
|
||||||
|
/* It is initialized externally, just reads the status.*/
|
||||||
|
if (blkGetDriverState(&MSBLKD[0]) != BLK_READY)
|
||||||
|
return RES_NOTRDY;
|
||||||
|
if (usbhmsdLUNRead(&MSBLKD[0], sector, buff, count))
|
||||||
|
return RES_ERROR;
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
return RES_PARERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Write Sector(s) */
|
||||||
|
|
||||||
|
#if _USE_WRITE
|
||||||
|
DRESULT disk_write (
|
||||||
|
BYTE pdrv, /* Physical drive nmuber (0..) */
|
||||||
|
const BYTE *buff, /* Data to be written */
|
||||||
|
DWORD sector, /* Sector address (LBA) */
|
||||||
|
UINT count /* Number of sectors to write (1..255) */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
switch (pdrv) {
|
||||||
|
case MSDLUN0:
|
||||||
|
/* It is initialized externally, just reads the status.*/
|
||||||
|
if (blkGetDriverState(&MSBLKD[0]) != BLK_READY)
|
||||||
|
return RES_NOTRDY;
|
||||||
|
if (usbhmsdLUNWrite(&MSBLKD[0], sector, buff, count))
|
||||||
|
return RES_ERROR;
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
return RES_PARERR;
|
||||||
|
}
|
||||||
|
#endif /* _USE_WRITE */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Miscellaneous Functions */
|
||||||
|
|
||||||
|
#if _USE_IOCTL
|
||||||
|
DRESULT disk_ioctl (
|
||||||
|
BYTE pdrv, /* Physical drive nmuber (0..) */
|
||||||
|
BYTE cmd, /* Control code */
|
||||||
|
void *buff /* Buffer to send/receive control data */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
switch (pdrv) {
|
||||||
|
case MSDLUN0:
|
||||||
|
switch (cmd) {
|
||||||
|
case CTRL_SYNC:
|
||||||
|
return RES_OK;
|
||||||
|
case GET_SECTOR_COUNT:
|
||||||
|
*((DWORD *)buff) = MSBLKD[0].info.blk_num;
|
||||||
|
return RES_OK;
|
||||||
|
case GET_SECTOR_SIZE:
|
||||||
|
*((WORD *)buff) = MSBLKD[0].info.blk_size;
|
||||||
|
return RES_OK;
|
||||||
|
default:
|
||||||
|
return RES_PARERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RES_PARERR;
|
||||||
|
}
|
||||||
|
#endif /* _USE_IOCTL */
|
||||||
|
|
||||||
|
DWORD get_fattime(void) {
|
||||||
|
return ((uint32_t)0 | (1 << 16)) | (1 << 21); /* wrong but valid time */
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,341 @@
|
||||||
|
/*---------------------------------------------------------------------------/
|
||||||
|
/ FatFs - FAT file system module include file R0.10c (C)ChaN, 2014
|
||||||
|
/----------------------------------------------------------------------------/
|
||||||
|
/ FatFs module is a generic FAT file system module for small embedded systems.
|
||||||
|
/ This is a free software that opened for education, research and commercial
|
||||||
|
/ developments under license policy of following terms.
|
||||||
|
/
|
||||||
|
/ Copyright (C) 2014, ChaN, all right reserved.
|
||||||
|
/
|
||||||
|
/ * The FatFs module is a free software and there is NO WARRANTY.
|
||||||
|
/ * No restriction on use. You can use, modify and redistribute it for
|
||||||
|
/ personal, non-profit or commercial product UNDER YOUR RESPONSIBILITY.
|
||||||
|
/ * Redistributions of source code must retain the above copyright notice.
|
||||||
|
/
|
||||||
|
/----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef _FATFS
|
||||||
|
#define _FATFS 80376 /* Revision ID */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "integer.h" /* Basic integer types */
|
||||||
|
#include "ffconf.h" /* FatFs configuration options */
|
||||||
|
#if _FATFS != _FFCONF
|
||||||
|
#error Wrong configuration file (ffconf.h).
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Definitions of volume management */
|
||||||
|
|
||||||
|
#if _MULTI_PARTITION /* Multiple partition configuration */
|
||||||
|
typedef struct {
|
||||||
|
BYTE pd; /* Physical drive number */
|
||||||
|
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
|
||||||
|
} PARTITION;
|
||||||
|
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
|
||||||
|
#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */
|
||||||
|
#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */
|
||||||
|
|
||||||
|
#else /* Single partition configuration */
|
||||||
|
#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */
|
||||||
|
#define LD2PT(vol) 0 /* Find first valid partition or in SFD */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Type of path name strings on FatFs API */
|
||||||
|
|
||||||
|
#if _LFN_UNICODE /* Unicode string */
|
||||||
|
#if !_USE_LFN
|
||||||
|
#error _LFN_UNICODE must be 0 at non-LFN cfg.
|
||||||
|
#endif
|
||||||
|
#ifndef _INC_TCHAR
|
||||||
|
typedef WCHAR TCHAR;
|
||||||
|
#define _T(x) L ## x
|
||||||
|
#define _TEXT(x) L ## x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else /* ANSI/OEM string */
|
||||||
|
#ifndef _INC_TCHAR
|
||||||
|
typedef char TCHAR;
|
||||||
|
#define _T(x) x
|
||||||
|
#define _TEXT(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* File system object structure (FATFS) */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
BYTE fs_type; /* FAT sub-type (0:Not mounted) */
|
||||||
|
BYTE drv; /* Physical drive number */
|
||||||
|
BYTE csize; /* Sectors per cluster (1,2,4...128) */
|
||||||
|
BYTE n_fats; /* Number of FAT copies (1 or 2) */
|
||||||
|
BYTE wflag; /* win[] flag (b0:dirty) */
|
||||||
|
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
|
||||||
|
WORD id; /* File system mount ID */
|
||||||
|
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
|
||||||
|
#if _MAX_SS != _MIN_SS
|
||||||
|
WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */
|
||||||
|
#endif
|
||||||
|
#if _FS_REENTRANT
|
||||||
|
_SYNC_t sobj; /* Identifier of sync object */
|
||||||
|
#endif
|
||||||
|
#if !_FS_READONLY
|
||||||
|
DWORD last_clust; /* Last allocated cluster */
|
||||||
|
DWORD free_clust; /* Number of free clusters */
|
||||||
|
#endif
|
||||||
|
#if _FS_RPATH
|
||||||
|
DWORD cdir; /* Current directory start cluster (0:root) */
|
||||||
|
#endif
|
||||||
|
DWORD n_fatent; /* Number of FAT entries, = number of clusters + 2 */
|
||||||
|
DWORD fsize; /* Sectors per FAT */
|
||||||
|
DWORD volbase; /* Volume start sector */
|
||||||
|
DWORD fatbase; /* FAT start sector */
|
||||||
|
DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */
|
||||||
|
DWORD database; /* Data start sector */
|
||||||
|
DWORD winsect; /* Current sector appearing in the win[] */
|
||||||
|
BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
||||||
|
} FATFS;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* File object structure (FIL) */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
FATFS* fs; /* Pointer to the related file system object (**do not change order**) */
|
||||||
|
WORD id; /* Owner file system mount ID (**do not change order**) */
|
||||||
|
BYTE flag; /* Status flags */
|
||||||
|
BYTE err; /* Abort flag (error code) */
|
||||||
|
DWORD fptr; /* File read/write pointer (Zeroed on file open) */
|
||||||
|
DWORD fsize; /* File size */
|
||||||
|
DWORD sclust; /* File start cluster (0:no cluster chain, always 0 when fsize is 0) */
|
||||||
|
DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */
|
||||||
|
DWORD dsect; /* Sector number appearing in buf[] (0:invalid) */
|
||||||
|
#if !_FS_READONLY
|
||||||
|
DWORD dir_sect; /* Sector number containing the directory entry */
|
||||||
|
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
|
||||||
|
#endif
|
||||||
|
#if _USE_FASTSEEK
|
||||||
|
DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */
|
||||||
|
#endif
|
||||||
|
#if _FS_LOCK
|
||||||
|
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
|
||||||
|
#endif
|
||||||
|
#if !_FS_TINY
|
||||||
|
BYTE buf[_MAX_SS]; /* File private data read/write window */
|
||||||
|
#endif
|
||||||
|
} FIL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Directory object structure (DIR) */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
FATFS* fs; /* Pointer to the owner file system object (**do not change order**) */
|
||||||
|
WORD id; /* Owner file system mount ID (**do not change order**) */
|
||||||
|
WORD index; /* Current read/write index number */
|
||||||
|
DWORD sclust; /* Table start cluster (0:Root dir) */
|
||||||
|
DWORD clust; /* Current cluster */
|
||||||
|
DWORD sect; /* Current sector */
|
||||||
|
BYTE* dir; /* Pointer to the current SFN entry in the win[] */
|
||||||
|
BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
|
||||||
|
#if _FS_LOCK
|
||||||
|
UINT lockid; /* File lock ID (index of file semaphore table Files[]) */
|
||||||
|
#endif
|
||||||
|
#if _USE_LFN
|
||||||
|
WCHAR* lfn; /* Pointer to the LFN working buffer */
|
||||||
|
WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */
|
||||||
|
#endif
|
||||||
|
} DIR;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* File status structure (FILINFO) */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
DWORD fsize; /* File size */
|
||||||
|
WORD fdate; /* Last modified date */
|
||||||
|
WORD ftime; /* Last modified time */
|
||||||
|
BYTE fattrib; /* Attribute */
|
||||||
|
TCHAR fname[13]; /* Short file name (8.3 format) */
|
||||||
|
#if _USE_LFN
|
||||||
|
TCHAR* lfname; /* Pointer to the LFN buffer */
|
||||||
|
UINT lfsize; /* Size of LFN buffer in TCHAR */
|
||||||
|
#endif
|
||||||
|
} FILINFO;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* File function return code (FRESULT) */
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FR_OK = 0, /* (0) Succeeded */
|
||||||
|
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
|
||||||
|
FR_INT_ERR, /* (2) Assertion failed */
|
||||||
|
FR_NOT_READY, /* (3) The physical drive cannot work */
|
||||||
|
FR_NO_FILE, /* (4) Could not find the file */
|
||||||
|
FR_NO_PATH, /* (5) Could not find the path */
|
||||||
|
FR_INVALID_NAME, /* (6) The path name format is invalid */
|
||||||
|
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
|
||||||
|
FR_EXIST, /* (8) Access denied due to prohibited access */
|
||||||
|
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
|
||||||
|
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
|
||||||
|
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
|
||||||
|
FR_NOT_ENABLED, /* (12) The volume has no work area */
|
||||||
|
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
|
||||||
|
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
|
||||||
|
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
||||||
|
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
||||||
|
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
||||||
|
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */
|
||||||
|
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
|
||||||
|
} FRESULT;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------*/
|
||||||
|
/* FatFs module application interface */
|
||||||
|
|
||||||
|
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
|
||||||
|
FRESULT f_close (FIL* fp); /* Close an open file object */
|
||||||
|
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */
|
||||||
|
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */
|
||||||
|
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
||||||
|
FRESULT f_lseek (FIL* fp, DWORD ofs); /* Move file pointer of a file object */
|
||||||
|
FRESULT f_truncate (FIL* fp); /* Truncate file */
|
||||||
|
FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */
|
||||||
|
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
|
||||||
|
FRESULT f_closedir (DIR* dp); /* Close an open directory */
|
||||||
|
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
|
||||||
|
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
|
||||||
|
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
|
||||||
|
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
|
||||||
|
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
|
||||||
|
FRESULT f_chmod (const TCHAR* path, BYTE value, BYTE mask); /* Change attribute of the file/dir */
|
||||||
|
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change times-tamp of the file/dir */
|
||||||
|
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
|
||||||
|
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
|
||||||
|
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
|
||||||
|
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
|
||||||
|
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
|
||||||
|
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
|
||||||
|
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
||||||
|
FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */
|
||||||
|
FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */
|
||||||
|
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
|
||||||
|
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
|
||||||
|
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
|
||||||
|
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
|
||||||
|
|
||||||
|
#define f_eof(fp) ((int)((fp)->fptr == (fp)->fsize))
|
||||||
|
#define f_error(fp) ((fp)->err)
|
||||||
|
#define f_tell(fp) ((fp)->fptr)
|
||||||
|
#define f_size(fp) ((fp)->fsize)
|
||||||
|
|
||||||
|
#ifndef EOF
|
||||||
|
#define EOF (-1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------*/
|
||||||
|
/* Additional user defined functions */
|
||||||
|
|
||||||
|
/* RTC function */
|
||||||
|
#if !_FS_READONLY && !_FS_NORTC
|
||||||
|
DWORD get_fattime (void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Unicode support functions */
|
||||||
|
#if _USE_LFN /* Unicode - OEM code conversion */
|
||||||
|
WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */
|
||||||
|
WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */
|
||||||
|
#if _USE_LFN == 3 /* Memory functions */
|
||||||
|
void* ff_memalloc (UINT msize); /* Allocate memory block */
|
||||||
|
void ff_memfree (void* mblock); /* Free memory block */
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Sync functions */
|
||||||
|
#if _FS_REENTRANT
|
||||||
|
int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */
|
||||||
|
int ff_req_grant (_SYNC_t sobj); /* Lock sync object */
|
||||||
|
void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */
|
||||||
|
int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------*/
|
||||||
|
/* Flags and offset address */
|
||||||
|
|
||||||
|
|
||||||
|
/* File access control and file status flags (FIL.flag) */
|
||||||
|
|
||||||
|
#define FA_READ 0x01
|
||||||
|
#define FA_OPEN_EXISTING 0x00
|
||||||
|
|
||||||
|
#if !_FS_READONLY
|
||||||
|
#define FA_WRITE 0x02
|
||||||
|
#define FA_CREATE_NEW 0x04
|
||||||
|
#define FA_CREATE_ALWAYS 0x08
|
||||||
|
#define FA_OPEN_ALWAYS 0x10
|
||||||
|
#define FA__WRITTEN 0x20
|
||||||
|
#define FA__DIRTY 0x40
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* FAT sub type (FATFS.fs_type) */
|
||||||
|
|
||||||
|
#define FS_FAT12 1
|
||||||
|
#define FS_FAT16 2
|
||||||
|
#define FS_FAT32 3
|
||||||
|
|
||||||
|
|
||||||
|
/* File attribute bits for directory entry */
|
||||||
|
|
||||||
|
#define AM_RDO 0x01 /* Read only */
|
||||||
|
#define AM_HID 0x02 /* Hidden */
|
||||||
|
#define AM_SYS 0x04 /* System */
|
||||||
|
#define AM_VOL 0x08 /* Volume label */
|
||||||
|
#define AM_LFN 0x0F /* LFN entry */
|
||||||
|
#define AM_DIR 0x10 /* Directory */
|
||||||
|
#define AM_ARC 0x20 /* Archive */
|
||||||
|
#define AM_MASK 0x3F /* Mask of defined bits */
|
||||||
|
|
||||||
|
|
||||||
|
/* Fast seek feature */
|
||||||
|
#define CREATE_LINKMAP 0xFFFFFFFF
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------*/
|
||||||
|
/* Multi-byte word access macros */
|
||||||
|
|
||||||
|
#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */
|
||||||
|
#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr))
|
||||||
|
#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr))
|
||||||
|
#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
|
||||||
|
#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
|
||||||
|
#else /* Use byte-by-byte access to the FAT structure */
|
||||||
|
#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
|
||||||
|
#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr))
|
||||||
|
#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8)
|
||||||
|
#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _FATFS */
|
|
@ -0,0 +1,271 @@
|
||||||
|
/*---------------------------------------------------------------------------/
|
||||||
|
/ FatFs - FAT file system module configuration file R0.10c (C)ChaN, 2014
|
||||||
|
/---------------------------------------------------------------------------*/
|
||||||
|
#include "ch.h"
|
||||||
|
|
||||||
|
#define _FFCONF 80376 /* Revision ID */
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------/
|
||||||
|
/ Functions and Buffer Configurations
|
||||||
|
/---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define _FS_TINY 0
|
||||||
|
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
||||||
|
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS
|
||||||
|
/ bytes. Instead of private sector buffer eliminated from the file object,
|
||||||
|
/ common sector buffer in the file system object (FATFS) is used for the file
|
||||||
|
/ data transfer. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _FS_READONLY 0
|
||||||
|
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
|
||||||
|
/ Read-only configuration removes basic writing API functions, f_write(),
|
||||||
|
/ f_sync(), f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(),
|
||||||
|
/ f_getfree() and optional writing functions as well. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _FS_MINIMIZE 0
|
||||||
|
/* This option defines minimization level to remove some API functions.
|
||||||
|
/
|
||||||
|
/ 0: All basic functions are enabled.
|
||||||
|
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(),
|
||||||
|
/ f_truncate() and f_rename() function are removed.
|
||||||
|
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
|
||||||
|
/ 3: f_lseek() function is removed in addition to 2. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _USE_STRFUNC 0
|
||||||
|
/* This option switches string functions, f_gets(), f_putc(), f_puts() and
|
||||||
|
/ f_printf().
|
||||||
|
/
|
||||||
|
/ 0: Disable string functions.
|
||||||
|
/ 1: Enable without LF-CRLF conversion.
|
||||||
|
/ 2: Enable with LF-CRLF conversion. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _USE_MKFS 0
|
||||||
|
/* This option switches f_mkfs() function. (0:Disable or 1:Enable)
|
||||||
|
/ To enable it, also _FS_READONLY need to be set to 0. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _USE_FASTSEEK 0
|
||||||
|
/* This option switches fast seek feature. (0:Disable or 1:Enable) */
|
||||||
|
|
||||||
|
|
||||||
|
#define _USE_LABEL 0
|
||||||
|
/* This option switches volume label functions, f_getlabel() and f_setlabel().
|
||||||
|
/ (0:Disable or 1:Enable) */
|
||||||
|
|
||||||
|
|
||||||
|
#define _USE_FORWARD 0
|
||||||
|
/* This option switches f_forward() function. (0:Disable or 1:Enable) */
|
||||||
|
/* To enable it, also _FS_TINY need to be set to 1. */
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------/
|
||||||
|
/ Locale and Namespace Configurations
|
||||||
|
/---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define _CODE_PAGE 437
|
||||||
|
/* This option specifies the OEM code page to be used on the target system.
|
||||||
|
/ Incorrect setting of the code page can cause a file open failure.
|
||||||
|
/
|
||||||
|
/ 932 - Japanese Shift_JIS (DBCS, OEM, Windows)
|
||||||
|
/ 936 - Simplified Chinese GBK (DBCS, OEM, Windows)
|
||||||
|
/ 949 - Korean (DBCS, OEM, Windows)
|
||||||
|
/ 950 - Traditional Chinese Big5 (DBCS, OEM, Windows)
|
||||||
|
/ 1250 - Central Europe (Windows)
|
||||||
|
/ 1251 - Cyrillic (Windows)
|
||||||
|
/ 1252 - Latin 1 (Windows)
|
||||||
|
/ 1253 - Greek (Windows)
|
||||||
|
/ 1254 - Turkish (Windows)
|
||||||
|
/ 1255 - Hebrew (Windows)
|
||||||
|
/ 1256 - Arabic (Windows)
|
||||||
|
/ 1257 - Baltic (Windows)
|
||||||
|
/ 1258 - Vietnam (OEM, Windows)
|
||||||
|
/ 437 - U.S. (OEM)
|
||||||
|
/ 720 - Arabic (OEM)
|
||||||
|
/ 737 - Greek (OEM)
|
||||||
|
/ 775 - Baltic (OEM)
|
||||||
|
/ 850 - Multilingual Latin 1 (OEM)
|
||||||
|
/ 858 - Multilingual Latin 1 + Euro (OEM)
|
||||||
|
/ 852 - Latin 2 (OEM)
|
||||||
|
/ 855 - Cyrillic (OEM)
|
||||||
|
/ 866 - Russian (OEM)
|
||||||
|
/ 857 - Turkish (OEM)
|
||||||
|
/ 862 - Hebrew (OEM)
|
||||||
|
/ 874 - Thai (OEM, Windows)
|
||||||
|
/ 1 - ASCII (No extended character. Valid for only non-LFN configuration.) */
|
||||||
|
|
||||||
|
|
||||||
|
#define _USE_LFN 0
|
||||||
|
#define _MAX_LFN 255
|
||||||
|
/* The _USE_LFN option switches the LFN feature.
|
||||||
|
/
|
||||||
|
/ 0: Disable LFN feature. _MAX_LFN has no effect.
|
||||||
|
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
|
||||||
|
/ 2: Enable LFN with dynamic working buffer on the STACK.
|
||||||
|
/ 3: Enable LFN with dynamic working buffer on the HEAP.
|
||||||
|
/
|
||||||
|
/ When enable the LFN feature, Unicode handling functions (option/unicode.c) must
|
||||||
|
/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes.
|
||||||
|
/ When use stack for the working buffer, take care on stack overflow. When use heap
|
||||||
|
/ memory for the working buffer, memory management functions, ff_memalloc() and
|
||||||
|
/ ff_memfree(), must be added to the project. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _LFN_UNICODE 0
|
||||||
|
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode)
|
||||||
|
/ To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE
|
||||||
|
/ to 1. This option also affects behavior of string I/O functions. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _STRF_ENCODE 3
|
||||||
|
/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to
|
||||||
|
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
|
||||||
|
/
|
||||||
|
/ 0: ANSI/OEM
|
||||||
|
/ 1: UTF-16LE
|
||||||
|
/ 2: UTF-16BE
|
||||||
|
/ 3: UTF-8
|
||||||
|
/
|
||||||
|
/ When _LFN_UNICODE is 0, this option has no effect. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _FS_RPATH 0
|
||||||
|
/* This option configures relative path feature.
|
||||||
|
/
|
||||||
|
/ 0: Disable relative path feature and remove related functions.
|
||||||
|
/ 1: Enable relative path feature. f_chdir() and f_chdrive() are available.
|
||||||
|
/ 2: f_getcwd() function is available in addition to 1.
|
||||||
|
/
|
||||||
|
/ Note that directory items read via f_readdir() are affected by this option. */
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------/
|
||||||
|
/ Drive/Volume Configurations
|
||||||
|
/---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define _VOLUMES 1
|
||||||
|
/* Number of volumes (logical drives) to be used. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _STR_VOLUME_ID 0
|
||||||
|
#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"
|
||||||
|
/* _STR_VOLUME_ID option switches string volume ID feature.
|
||||||
|
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
|
||||||
|
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
|
||||||
|
/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for
|
||||||
|
/ the drive ID strings are: A-Z and 0-9. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _MULTI_PARTITION 0
|
||||||
|
/* This option switches multi-partition feature. By default (0), each logical drive
|
||||||
|
/ number is bound to the same physical drive number and only an FAT volume found on
|
||||||
|
/ the physical drive will be mounted. When multi-partition feature is enabled (1),
|
||||||
|
/ each logical drive number is bound to arbitrary physical drive and partition
|
||||||
|
/ listed in the VolToPart[]. Also f_fdisk() funciton will be enabled. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _MIN_SS 512
|
||||||
|
#define _MAX_SS 512
|
||||||
|
/* These options configure the range of sector size to be supported. (512, 1024,
|
||||||
|
/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and
|
||||||
|
/ harddisk. But a larger value may be required for on-board flash memory and some
|
||||||
|
/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured
|
||||||
|
/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the
|
||||||
|
/ disk_ioctl() function. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _USE_TRIM 0
|
||||||
|
/* This option switches ATA-TRIM feature. (0:Disable or 1:Enable)
|
||||||
|
/ To enable Trim feature, also CTRL_TRIM command should be implemented to the
|
||||||
|
/ disk_ioctl() function. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _FS_NOFSINFO 0
|
||||||
|
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
|
||||||
|
/ option, and f_getfree() function at first time after volume mount will force
|
||||||
|
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
|
||||||
|
/
|
||||||
|
/ bit0=0: Use free cluster count in the FSINFO if available.
|
||||||
|
/ bit0=1: Do not trust free cluster count in the FSINFO.
|
||||||
|
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
|
||||||
|
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------/
|
||||||
|
/ System Configurations
|
||||||
|
/---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define _FS_NORTC 0
|
||||||
|
#define _NORTC_MON 11
|
||||||
|
#define _NORTC_MDAY 9
|
||||||
|
#define _NORTC_YEAR 2014
|
||||||
|
/* The _FS_NORTC option switches timestamp feature. If the system does not have
|
||||||
|
/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable
|
||||||
|
/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp
|
||||||
|
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR.
|
||||||
|
/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need
|
||||||
|
/ to be added to the project to read current time form RTC. _NORTC_MON,
|
||||||
|
/ _NORTC_MDAY and _NORTC_YEAR have no effect.
|
||||||
|
/ These options have no effect at read-only configuration (_FS_READONLY == 1). */
|
||||||
|
|
||||||
|
|
||||||
|
#define _FS_LOCK 0
|
||||||
|
/* The _FS_LOCK option switches file lock feature to control duplicated file open
|
||||||
|
/ and illegal operation to open objects. This option must be 0 when _FS_READONLY
|
||||||
|
/ is 1.
|
||||||
|
/
|
||||||
|
/ 0: Disable file lock feature. To avoid volume corruption, application program
|
||||||
|
/ should avoid illegal open, remove and rename to the open objects.
|
||||||
|
/ >0: Enable file lock feature. The value defines how many files/sub-directories
|
||||||
|
/ can be opened simultaneously under file lock control. Note that the file
|
||||||
|
/ lock feature is independent of re-entrancy. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _FS_REENTRANT 0
|
||||||
|
#define _FS_TIMEOUT S2ST(10)
|
||||||
|
typedef semaphore_t * _SYNC_t;
|
||||||
|
/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs
|
||||||
|
/ module itself. Note that regardless of this option, file access to different
|
||||||
|
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
|
||||||
|
/ and f_fdisk() function, are always not re-entrant. Only file/directory access
|
||||||
|
/ to the same volume is under control of this feature.
|
||||||
|
/
|
||||||
|
/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect.
|
||||||
|
/ 1: Enable re-entrancy. Also user provided synchronization handlers,
|
||||||
|
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
|
||||||
|
/ function, must be added to the project. Samples are available in
|
||||||
|
/ option/syscall.c.
|
||||||
|
/
|
||||||
|
/ The _FS_TIMEOUT defines timeout period in unit of time tick.
|
||||||
|
/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
|
||||||
|
/ SemaphoreHandle_t and etc.. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _WORD_ACCESS 0
|
||||||
|
/* The _WORD_ACCESS option is an only platform dependent option. It defines
|
||||||
|
/ which access method is used to the word data on the FAT volume.
|
||||||
|
/
|
||||||
|
/ 0: Byte-by-byte access. Always compatible with all platforms.
|
||||||
|
/ 1: Word access. Do not choose this unless under both the following conditions.
|
||||||
|
/
|
||||||
|
/ * Address misaligned memory access is always allowed to ALL instructions.
|
||||||
|
/ * Byte order on the memory is little-endian.
|
||||||
|
/
|
||||||
|
/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size.
|
||||||
|
/ Following table shows allowable settings of some processor types.
|
||||||
|
/
|
||||||
|
/ ARM7TDMI 0 ColdFire 0 V850E 0
|
||||||
|
/ Cortex-M3 0 Z80 0/1 V850ES 0/1
|
||||||
|
/ Cortex-M0 0 x86 0/1 TLCS-870 0/1
|
||||||
|
/ AVR 0/1 RX600(LE) 0/1 TLCS-900 0/1
|
||||||
|
/ AVR32 0 RL78 0 R32C 0
|
||||||
|
/ PIC18 0/1 SH-2 0 M16C 0/1
|
||||||
|
/ PIC24 0 H8S 0 MSP430 0
|
||||||
|
/ PIC32 0 H8/300H 0 8051 0/1
|
||||||
|
*/
|
||||||
|
|
|
@ -0,0 +1,343 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file templates/halconf.h
|
||||||
|
* @brief HAL configuration header.
|
||||||
|
* @details HAL configuration file, this file allows to enable or disable the
|
||||||
|
* various device drivers from your application. You may also use
|
||||||
|
* this file in order to override the device drivers default settings.
|
||||||
|
*
|
||||||
|
* @addtogroup HAL_CONF
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _HALCONF_H_
|
||||||
|
#define _HALCONF_H_
|
||||||
|
|
||||||
|
#include "mcuconf.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the PAL subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_PAL TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the ADC subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_ADC FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the CAN subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_CAN FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the DAC subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_DAC) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_DAC FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the EXT subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_EXT) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_EXT FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the GPT subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_GPT FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the I2C subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_I2C FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the I2S subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_I2S) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_I2S FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the ICU subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_ICU FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the MAC subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_MAC FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the MMC_SPI subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_MMC_SPI FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the PWM subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_PWM FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the RTC subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_RTC FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the SDC subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_SDC FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the SERIAL subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_SERIAL TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the SERIAL over USB subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_SERIAL_USB FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the SPI subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_SPI FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the UART subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_UART) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_UART FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the USB subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_USB) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_USB FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the WDG subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_WDG) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_WDG FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* ADC driver related settings. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables synchronous APIs.
|
||||||
|
* @note Disabling this option saves both code and data space.
|
||||||
|
*/
|
||||||
|
#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__)
|
||||||
|
#define ADC_USE_WAIT TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs.
|
||||||
|
* @note Disabling this option saves both code and data space.
|
||||||
|
*/
|
||||||
|
#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
|
||||||
|
#define ADC_USE_MUTUAL_EXCLUSION TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* CAN driver related settings. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sleep mode related APIs inclusion switch.
|
||||||
|
*/
|
||||||
|
#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__)
|
||||||
|
#define CAN_USE_SLEEP_MODE TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* I2C driver related settings. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the mutual exclusion APIs on the I2C bus.
|
||||||
|
*/
|
||||||
|
#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
|
||||||
|
#define I2C_USE_MUTUAL_EXCLUSION TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* MAC driver related settings. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables an event sources for incoming packets.
|
||||||
|
*/
|
||||||
|
#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__)
|
||||||
|
#define MAC_USE_ZERO_COPY FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables an event sources for incoming packets.
|
||||||
|
*/
|
||||||
|
#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__)
|
||||||
|
#define MAC_USE_EVENTS TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* MMC_SPI driver related settings. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delays insertions.
|
||||||
|
* @details If enabled this options inserts delays into the MMC waiting
|
||||||
|
* routines releasing some extra CPU time for the threads with
|
||||||
|
* lower priority, this may slow down the driver a bit however.
|
||||||
|
* This option is recommended also if the SPI driver does not
|
||||||
|
* use a DMA channel and heavily loads the CPU.
|
||||||
|
*/
|
||||||
|
#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__)
|
||||||
|
#define MMC_NICE_WAITING TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* SDC driver related settings. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Number of initialization attempts before rejecting the card.
|
||||||
|
* @note Attempts are performed at 10mS intervals.
|
||||||
|
*/
|
||||||
|
#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__)
|
||||||
|
#define SDC_INIT_RETRY 100
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Include support for MMC cards.
|
||||||
|
* @note MMC support is not yet implemented so this option must be kept
|
||||||
|
* at @p FALSE.
|
||||||
|
*/
|
||||||
|
#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__)
|
||||||
|
#define SDC_MMC_SUPPORT FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delays insertions.
|
||||||
|
* @details If enabled this options inserts delays into the MMC waiting
|
||||||
|
* routines releasing some extra CPU time for the threads with
|
||||||
|
* lower priority, this may slow down the driver a bit however.
|
||||||
|
*/
|
||||||
|
#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__)
|
||||||
|
#define SDC_NICE_WAITING TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* SERIAL driver related settings. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default bit rate.
|
||||||
|
* @details Configuration parameter, this is the baud rate selected for the
|
||||||
|
* default configuration.
|
||||||
|
*/
|
||||||
|
#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__)
|
||||||
|
#define SERIAL_DEFAULT_BITRATE 115200
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Serial buffers size.
|
||||||
|
* @details Configuration parameter, you can change the depth of the queue
|
||||||
|
* buffers depending on the requirements of your application.
|
||||||
|
* @note The default is 64 bytes for both the transmission and receive
|
||||||
|
* buffers.
|
||||||
|
*/
|
||||||
|
#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
|
||||||
|
#define SERIAL_BUFFERS_SIZE 64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* SERIAL_USB driver related setting. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Serial over USB buffers size.
|
||||||
|
* @details Configuration parameter, the buffer size must be a multiple of
|
||||||
|
* the USB data endpoint maximum packet size.
|
||||||
|
* @note The default is 64 bytes for both the transmission and receive
|
||||||
|
* buffers.
|
||||||
|
*/
|
||||||
|
#if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__)
|
||||||
|
#define SERIAL_USB_BUFFERS_SIZE 256
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* SPI driver related settings. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables synchronous APIs.
|
||||||
|
* @note Disabling this option saves both code and data space.
|
||||||
|
*/
|
||||||
|
#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
|
||||||
|
#define SPI_USE_WAIT TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
|
||||||
|
* @note Disabling this option saves both code and data space.
|
||||||
|
*/
|
||||||
|
#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
|
||||||
|
#define SPI_USE_MUTUAL_EXCLUSION TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "halconf_community.h"
|
||||||
|
|
||||||
|
#endif /* _HALCONF_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,195 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2014 Uladzimir Pylinsky aka barthess
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _HALCONF_COMMUNITY_H_
|
||||||
|
#define _HALCONF_COMMUNITY_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the community overlay.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_COMMUNITY) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_COMMUNITY TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the FSMC subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_FSMC) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_FSMC FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the NAND subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_NAND) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_NAND FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the 1-wire subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_ONEWIRE) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_ONEWIRE FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the EICU subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_EICU) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_EICU FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the CRC subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_CRC) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_CRC FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the IWDG subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_IWDG) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_IWDG FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the TIMCAP subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_TIMCAP) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_TIMCAP FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the USBH subsystem.
|
||||||
|
*/
|
||||||
|
#if !defined(HAL_USE_USBH) || defined(__DOXYGEN__)
|
||||||
|
#define HAL_USE_USBH TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* USBH driver related settings. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/* main driver */
|
||||||
|
#define HAL_USBH_PORT_DEBOUNCE_TIME 200
|
||||||
|
#define HAL_USBH_PORT_RESET_TIMEOUT 500
|
||||||
|
#define HAL_USBH_DEVICE_ADDRESS_STABILIZATION 20
|
||||||
|
|
||||||
|
/* MSD */
|
||||||
|
#define HAL_USBH_USE_MSD 1
|
||||||
|
|
||||||
|
#define HAL_USBHMSD_MAX_LUNS 1
|
||||||
|
#define HAL_USBHMSD_MAX_INSTANCES 1
|
||||||
|
|
||||||
|
/* IAD */
|
||||||
|
#define HAL_USBH_USE_FTDI 1
|
||||||
|
|
||||||
|
#define HAL_USBHFTDI_MAX_PORTS 1
|
||||||
|
#define HAL_USBHFTDI_MAX_INSTANCES 1
|
||||||
|
#define HAL_USBHFTDI_DEFAULT_SPEED 9600
|
||||||
|
#define HAL_USBHFTDI_DEFAULT_FRAMING (USBHFTDI_FRAMING_DATABITS_8 | USBHFTDI_FRAMING_PARITY_NONE | USBHFTDI_FRAMING_STOP_BITS_1)
|
||||||
|
#define HAL_USBHFTDI_DEFAULT_HANDSHAKE USBHFTDI_HANDSHAKE_NONE
|
||||||
|
#define HAL_USBHFTDI_DEFAULT_XON 0x11
|
||||||
|
#define HAL_USBHFTDI_DEFAULT_XOFF 0x13
|
||||||
|
|
||||||
|
|
||||||
|
/* IAD */
|
||||||
|
#define HAL_USBH_USE_IAD 0
|
||||||
|
|
||||||
|
/* UVC */
|
||||||
|
#define HAL_USBH_USE_UVC 0
|
||||||
|
|
||||||
|
#define HAL_USBHUVC_MAX_INSTANCES 1
|
||||||
|
#define HAL_USBHUVC_MAX_MAILBOX_SZ 70
|
||||||
|
#define HAL_USBHUVC_WORK_RAM_SIZE 20000
|
||||||
|
#define HAL_USBHUVC_STATUS_PACKETS_COUNT 10
|
||||||
|
|
||||||
|
|
||||||
|
/* HUB */
|
||||||
|
#define HAL_USBH_USE_HUB 1
|
||||||
|
|
||||||
|
#define HAL_USBHHUB_MAX_INSTANCES 1
|
||||||
|
#define HAL_USBHHUB_MAX_PORTS 6
|
||||||
|
|
||||||
|
|
||||||
|
/* debug */
|
||||||
|
#define USBH_DEBUG_ENABLE 1
|
||||||
|
#define USBH_DEBUG_USBHD USBHD1
|
||||||
|
#define USBH_DEBUG_SD SD2
|
||||||
|
#define USBH_DEBUG_BUFFER 25000
|
||||||
|
|
||||||
|
#define USBH_DEBUG_ENABLE_TRACE 0
|
||||||
|
#define USBH_DEBUG_ENABLE_INFO 1
|
||||||
|
#define USBH_DEBUG_ENABLE_WARNINGS 1
|
||||||
|
#define USBH_DEBUG_ENABLE_ERRORS 1
|
||||||
|
|
||||||
|
#define USBH_LLD_DEBUG_ENABLE_TRACE 0
|
||||||
|
#define USBH_LLD_DEBUG_ENABLE_INFO 1
|
||||||
|
#define USBH_LLD_DEBUG_ENABLE_WARNINGS 1
|
||||||
|
#define USBH_LLD_DEBUG_ENABLE_ERRORS 1
|
||||||
|
|
||||||
|
#define USBHHUB_DEBUG_ENABLE_TRACE 0
|
||||||
|
#define USBHHUB_DEBUG_ENABLE_INFO 1
|
||||||
|
#define USBHHUB_DEBUG_ENABLE_WARNINGS 1
|
||||||
|
#define USBHHUB_DEBUG_ENABLE_ERRORS 1
|
||||||
|
|
||||||
|
#define USBHMSD_DEBUG_ENABLE_TRACE 0
|
||||||
|
#define USBHMSD_DEBUG_ENABLE_INFO 1
|
||||||
|
#define USBHMSD_DEBUG_ENABLE_WARNINGS 1
|
||||||
|
#define USBHMSD_DEBUG_ENABLE_ERRORS 1
|
||||||
|
|
||||||
|
#define USBHUVC_DEBUG_ENABLE_TRACE 0
|
||||||
|
#define USBHUVC_DEBUG_ENABLE_INFO 1
|
||||||
|
#define USBHUVC_DEBUG_ENABLE_WARNINGS 1
|
||||||
|
#define USBHUVC_DEBUG_ENABLE_ERRORS 1
|
||||||
|
|
||||||
|
#define USBHFTDI_DEBUG_ENABLE_TRACE 0
|
||||||
|
#define USBHFTDI_DEBUG_ENABLE_INFO 1
|
||||||
|
#define USBHFTDI_DEBUG_ENABLE_WARNINGS 1
|
||||||
|
#define USBHFTDI_DEBUG_ENABLE_ERRORS 1
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* FSMCNAND driver related settings. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the @p nandAcquireBus() and @p nanReleaseBus() APIs.
|
||||||
|
* @note Disabling this option saves both code and data space.
|
||||||
|
*/
|
||||||
|
#if !defined(NAND_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
|
||||||
|
#define NAND_USE_MUTUAL_EXCLUSION TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* 1-wire driver related settings. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
/**
|
||||||
|
* @brief Enables strong pull up feature.
|
||||||
|
* @note Disabling this option saves both code and data space.
|
||||||
|
*/
|
||||||
|
#define ONEWIRE_USE_STRONG_PULLUP FALSE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables search ROM feature.
|
||||||
|
* @note Disabling this option saves both code and data space.
|
||||||
|
*/
|
||||||
|
#define ONEWIRE_USE_SEARCH_ROM TRUE
|
||||||
|
|
||||||
|
#endif /* _HALCONF_COMMUNITY_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*-------------------------------------------*/
|
||||||
|
/* Integer type definitions for FatFs module */
|
||||||
|
/*-------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef _FF_INTEGER
|
||||||
|
#define _FF_INTEGER
|
||||||
|
|
||||||
|
#ifdef _WIN32 /* FatFs development platform */
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
|
||||||
|
#else /* Embedded platform */
|
||||||
|
|
||||||
|
/* This type MUST be 8 bit */
|
||||||
|
typedef unsigned char BYTE;
|
||||||
|
|
||||||
|
/* These types MUST be 16 bit */
|
||||||
|
typedef short SHORT;
|
||||||
|
typedef unsigned short WORD;
|
||||||
|
typedef unsigned short WCHAR;
|
||||||
|
|
||||||
|
/* These types MUST be 16 bit or 32 bit */
|
||||||
|
typedef int INT;
|
||||||
|
typedef unsigned int UINT;
|
||||||
|
|
||||||
|
/* These types MUST be 32 bit */
|
||||||
|
typedef long LONG;
|
||||||
|
typedef unsigned long DWORD;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,488 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ch.h"
|
||||||
|
#include "hal.h"
|
||||||
|
#include "ff.h"
|
||||||
|
#include "usbh.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if HAL_USBH_USE_FTDI
|
||||||
|
#include "usbh/dev/ftdi.h"
|
||||||
|
#include "test.h"
|
||||||
|
#include "shell.h"
|
||||||
|
#include "chprintf.h"
|
||||||
|
|
||||||
|
static THD_WORKING_AREA(waTestFTDI, 1024);
|
||||||
|
|
||||||
|
#define SHELL_WA_SIZE THD_WORKING_AREA_SIZE(2048)
|
||||||
|
#define TEST_WA_SIZE THD_WORKING_AREA_SIZE(256)
|
||||||
|
|
||||||
|
static uint8_t buf[] =
|
||||||
|
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||||
|
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||||
|
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||||
|
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||||
|
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||||
|
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||||
|
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||||
|
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||||
|
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||||
|
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||||
|
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||||
|
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||||
|
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||||
|
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||||
|
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||||
|
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
|
||||||
|
|
||||||
|
static void cmd_mem(BaseSequentialStream *chp, int argc, char *argv[]) {
|
||||||
|
size_t n, size;
|
||||||
|
|
||||||
|
(void)argv;
|
||||||
|
if (argc > 0) {
|
||||||
|
chprintf(chp, "Usage: mem\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
n = chHeapStatus(NULL, &size);
|
||||||
|
chprintf(chp, "core free memory : %u bytes\r\n", chCoreGetStatusX());
|
||||||
|
chprintf(chp, "heap fragments : %u\r\n", n);
|
||||||
|
chprintf(chp, "heap free total : %u bytes\r\n", size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmd_threads(BaseSequentialStream *chp, int argc, char *argv[]) {
|
||||||
|
static const char *states[] = {CH_STATE_NAMES};
|
||||||
|
thread_t *tp;
|
||||||
|
|
||||||
|
(void)argv;
|
||||||
|
if (argc > 0) {
|
||||||
|
chprintf(chp, "Usage: threads\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
chprintf(chp, " addr stack prio refs state\r\n");
|
||||||
|
tp = chRegFirstThread();
|
||||||
|
do {
|
||||||
|
chprintf(chp, "%08lx %08lx %4lu %4lu %9s\r\n",
|
||||||
|
(uint32_t)tp, (uint32_t)tp->p_ctx.r13,
|
||||||
|
(uint32_t)tp->p_prio, (uint32_t)(tp->p_refs - 1),
|
||||||
|
states[tp->p_state]);
|
||||||
|
tp = chRegNextThread(tp);
|
||||||
|
} while (tp != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmd_test(BaseSequentialStream *chp, int argc, char *argv[]) {
|
||||||
|
thread_t *tp;
|
||||||
|
|
||||||
|
(void)argv;
|
||||||
|
if (argc > 0) {
|
||||||
|
chprintf(chp, "Usage: test\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tp = chThdCreateFromHeap(NULL, TEST_WA_SIZE, chThdGetPriorityX(),
|
||||||
|
TestThread, chp);
|
||||||
|
if (tp == NULL) {
|
||||||
|
chprintf(chp, "out of memory\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
chThdWait(tp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmd_write(BaseSequentialStream *chp, int argc, char *argv[]) {
|
||||||
|
|
||||||
|
(void)argv;
|
||||||
|
if (argc > 0) {
|
||||||
|
chprintf(chp, "Usage: write\r\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (chnGetTimeout((BaseChannel *)chp, TIME_IMMEDIATE) != Q_TIMEOUT) {
|
||||||
|
//flush
|
||||||
|
}
|
||||||
|
|
||||||
|
while (chnGetTimeout((BaseChannel *)chp, TIME_IMMEDIATE) == Q_TIMEOUT) {
|
||||||
|
chSequentialStreamWrite(&FTDIPD[0], buf, sizeof buf - 1);
|
||||||
|
}
|
||||||
|
chprintf(chp, "\r\n\nstopped\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static const ShellCommand commands[] = {
|
||||||
|
{"mem", cmd_mem},
|
||||||
|
{"threads", cmd_threads},
|
||||||
|
{"test", cmd_test},
|
||||||
|
{"write", cmd_write},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const ShellConfig shell_cfg1 = {
|
||||||
|
(BaseSequentialStream *)&FTDIPD[0],
|
||||||
|
commands
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ThreadTestFTDI(void *p) {
|
||||||
|
(void)p;
|
||||||
|
USBHFTDIPortDriver *const ftdipp = &FTDIPD[0];
|
||||||
|
|
||||||
|
shellInit();
|
||||||
|
|
||||||
|
start:
|
||||||
|
while (ftdipp->state != USBHFTDIP_STATE_ACTIVE) {
|
||||||
|
chThdSleepMilliseconds(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
usbDbgPuts("FTDI: Connected");
|
||||||
|
|
||||||
|
USBHFTDIPortConfig config = {
|
||||||
|
115200,
|
||||||
|
USBHFTDI_FRAMING_DATABITS_8 | USBHFTDI_FRAMING_PARITY_NONE | USBHFTDI_FRAMING_STOP_BITS_1,
|
||||||
|
USBHFTDI_HANDSHAKE_NONE,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
usbhftdipStart(ftdipp, &config);
|
||||||
|
|
||||||
|
//loopback
|
||||||
|
if (0) {
|
||||||
|
for(;;) {
|
||||||
|
msg_t m = chSequentialStreamGet(ftdipp);
|
||||||
|
if (m < MSG_OK) {
|
||||||
|
usbDbgPuts("FTDI: Disconnected");
|
||||||
|
goto start;
|
||||||
|
}
|
||||||
|
chSequentialStreamPut(ftdipp, (uint8_t)m);
|
||||||
|
if (m == 'q')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//shell test
|
||||||
|
if (1) {
|
||||||
|
thread_t *shelltp = NULL;
|
||||||
|
for(;;) {
|
||||||
|
if (ftdipp->state != USBHFTDIP_STATE_READY)
|
||||||
|
goto start;
|
||||||
|
if (!shelltp) {
|
||||||
|
shelltp = shellCreate(&shell_cfg1, SHELL_WA_SIZE, NORMALPRIO);
|
||||||
|
} else if (chThdTerminatedX(shelltp)) {
|
||||||
|
chThdRelease(shelltp);
|
||||||
|
if (ftdipp->state != USBHFTDIP_STATE_READY)
|
||||||
|
goto start;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
chThdSleepMilliseconds(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//FTDI uart RX to debug TX bridge
|
||||||
|
if (0) {
|
||||||
|
for(;;) {
|
||||||
|
msg_t m = chSequentialStreamGet(ftdipp);
|
||||||
|
if (m < MSG_OK) {
|
||||||
|
usbDbgPuts("FTDI: Disconnected");
|
||||||
|
goto start;
|
||||||
|
}
|
||||||
|
sdPut(&USBH_DEBUG_SD, (uint8_t)m);
|
||||||
|
if (m == 'q')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//write speed test
|
||||||
|
if (1) {
|
||||||
|
usbhftdipStop(ftdipp);
|
||||||
|
config.speed = 3000000;
|
||||||
|
usbhftdipStart(ftdipp, &config);
|
||||||
|
|
||||||
|
systime_t st, et;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 5; i++) {
|
||||||
|
uint32_t bytes = config.speed / 10;
|
||||||
|
uint32_t times = bytes / 1024;
|
||||||
|
st = chVTGetSystemTimeX();
|
||||||
|
while (times--) {
|
||||||
|
if (chSequentialStreamWrite(ftdipp, buf, 1024) < 1024) {
|
||||||
|
usbDbgPuts("FTDI: Disconnected");
|
||||||
|
goto start;
|
||||||
|
}
|
||||||
|
bytes -= 1024;
|
||||||
|
}
|
||||||
|
if (bytes) {
|
||||||
|
if (chSequentialStreamWrite(ftdipp, buf, bytes) < bytes) {
|
||||||
|
usbDbgPuts("FTDI: Disconnected");
|
||||||
|
goto start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
et = chVTGetSystemTimeX();
|
||||||
|
usbDbgPrintf("\tRate=%uB/s", (config.speed * 100) / (et - st));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//single character write test (tests the timer)
|
||||||
|
if (0) {
|
||||||
|
for (;;) {
|
||||||
|
if (chSequentialStreamPut(ftdipp, 'A') != MSG_OK) {
|
||||||
|
usbDbgPuts("FTDI: Disconnected");
|
||||||
|
goto start;
|
||||||
|
}
|
||||||
|
chThdSleepMilliseconds(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usbhftdipStop(ftdipp);
|
||||||
|
|
||||||
|
usbDbgPuts("FTDI: Tests done, restarting in 3s");
|
||||||
|
chThdSleepMilliseconds(3000);
|
||||||
|
|
||||||
|
goto start;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if HAL_USBH_USE_MSD
|
||||||
|
#include "usbh/dev/msd.h"
|
||||||
|
#include "ff.h"
|
||||||
|
|
||||||
|
static FATFS MSDLUN0FS;
|
||||||
|
static uint8_t fbuff[10240];
|
||||||
|
static FIL file;
|
||||||
|
|
||||||
|
static FRESULT scan_files(BaseSequentialStream *chp, char *path) {
|
||||||
|
FRESULT res;
|
||||||
|
FILINFO fno;
|
||||||
|
DIR dir;
|
||||||
|
int i;
|
||||||
|
char *fn;
|
||||||
|
|
||||||
|
#if _USE_LFN
|
||||||
|
fno.lfname = 0;
|
||||||
|
fno.lfsize = 0;
|
||||||
|
#endif
|
||||||
|
res = f_opendir(&dir, path);
|
||||||
|
if (res == FR_OK) {
|
||||||
|
i = strlen(path);
|
||||||
|
for (;;) {
|
||||||
|
res = f_readdir(&dir, &fno);
|
||||||
|
if (res != FR_OK || fno.fname[0] == 0)
|
||||||
|
break;
|
||||||
|
if (fno.fname[0] == '.')
|
||||||
|
continue;
|
||||||
|
fn = fno.fname;
|
||||||
|
if (fno.fattrib & AM_DIR) {
|
||||||
|
path[i++] = '/';
|
||||||
|
strcpy(&path[i], fn);
|
||||||
|
res = scan_files(chp, path);
|
||||||
|
if (res != FR_OK)
|
||||||
|
break;
|
||||||
|
path[--i] = 0;
|
||||||
|
} else {
|
||||||
|
usbDbgPrintf("FS: %s/%s", path, fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
static THD_WORKING_AREA(waTestMSD, 1024);
|
||||||
|
static void ThreadTestMSD(void *p) {
|
||||||
|
(void)p;
|
||||||
|
|
||||||
|
FATFS *fsp;
|
||||||
|
uint32_t clusters;
|
||||||
|
FRESULT res;
|
||||||
|
BaseSequentialStream * const chp = (BaseSequentialStream *)&USBH_DEBUG_SD;
|
||||||
|
blkstate_t state;
|
||||||
|
systime_t st, et;
|
||||||
|
uint32_t j;
|
||||||
|
|
||||||
|
start:
|
||||||
|
for(;;) {
|
||||||
|
chThdSleepMilliseconds(100);
|
||||||
|
|
||||||
|
chSysLock();
|
||||||
|
state = blkGetDriverState(&MSBLKD[0]);
|
||||||
|
chSysUnlock();
|
||||||
|
if (state != BLK_READY)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//raw read test
|
||||||
|
if (1) {
|
||||||
|
#define RAW_READ_SZ_MB 1
|
||||||
|
#define NBLOCKS (sizeof(fbuff) / 512)
|
||||||
|
#define NITERATIONS ((RAW_READ_SZ_MB * 1024UL * 1024UL) / sizeof(fbuff))
|
||||||
|
uint32_t start = 0;
|
||||||
|
chThdSetPriority(HIGHPRIO);
|
||||||
|
usbDbgPrintf("BLK: Raw read test (%dMB, %dB blocks)", RAW_READ_SZ_MB, sizeof(fbuff));
|
||||||
|
st = chVTGetSystemTime();
|
||||||
|
for (j = 0; j < NITERATIONS; j++) {
|
||||||
|
blkRead(&MSBLKD[0], start, fbuff, NBLOCKS);
|
||||||
|
start += NBLOCKS;
|
||||||
|
}
|
||||||
|
et = chVTGetSystemTime();
|
||||||
|
usbDbgPrintf("BLK: Raw read in %d ms, %dkB/s",
|
||||||
|
et - st,
|
||||||
|
(RAW_READ_SZ_MB * 1024UL * 1000) / (et - st));
|
||||||
|
chThdSetPriority(NORMALPRIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
usbDbgPuts("FS: Block driver ready, try mount...");
|
||||||
|
|
||||||
|
res = f_mount(&MSDLUN0FS, "0:", 1);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
usbDbgPuts("FS: Can't mount. Check file system.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
usbDbgPuts("FS: Mounted.");
|
||||||
|
|
||||||
|
res = f_getfree("0:", &clusters, &fsp);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
usbDbgPuts("FS: f_getfree() failed");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
usbDbgPrintf("FS: %lu free clusters, %lu sectors per cluster, %lu bytes free",
|
||||||
|
clusters, (uint32_t)MSDLUN0FS.csize,
|
||||||
|
clusters * (uint32_t)MSDLUN0FS.csize * MSBLKD[0].info.blk_size);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//FATFS test
|
||||||
|
if (1) {
|
||||||
|
UINT bw;
|
||||||
|
const uint8_t *src;
|
||||||
|
const uint8_t *const start = (uint8_t *)0x08000000;
|
||||||
|
const uint8_t *const top = (uint8_t *)0x08020000;
|
||||||
|
|
||||||
|
//write test
|
||||||
|
if (1) {
|
||||||
|
usbDbgPuts("FS: Write test (create file /test.dat, 1MB)");
|
||||||
|
f_open(&file, "/test.dat", FA_CREATE_ALWAYS | FA_WRITE);
|
||||||
|
src = start;
|
||||||
|
st = chVTGetSystemTime();
|
||||||
|
for (j = 0; j < 2048; j++) {
|
||||||
|
if (f_write(&file, src, 512, &bw) != FR_OK)
|
||||||
|
goto start;
|
||||||
|
src += bw;
|
||||||
|
if (src >= top)
|
||||||
|
src = start;
|
||||||
|
}
|
||||||
|
et = chVTGetSystemTime();
|
||||||
|
usbDbgPrintf("FS: Written 1MB in %d ms, %dkB/s",
|
||||||
|
et - st,
|
||||||
|
(1024UL*1000) / (et - st));
|
||||||
|
f_close(&file);
|
||||||
|
}
|
||||||
|
|
||||||
|
//read test
|
||||||
|
if (1) {
|
||||||
|
usbDbgPuts("FS: Read test (read file /test.dat, 1MB, compare)");
|
||||||
|
f_open(&file, "/test.dat", FA_READ);
|
||||||
|
src = start;
|
||||||
|
st = chVTGetSystemTime();
|
||||||
|
for (j = 0; j < 2048; j++) {
|
||||||
|
if (f_read(&file, fbuff, 512, &bw) != FR_OK)
|
||||||
|
goto start;
|
||||||
|
if (memcmp(src, fbuff, bw)) {
|
||||||
|
usbDbgPrintf("Compare error @%08x", (uint32_t)src);
|
||||||
|
goto start;
|
||||||
|
}
|
||||||
|
src += bw;
|
||||||
|
if (src >= top)
|
||||||
|
src = start;
|
||||||
|
}
|
||||||
|
et = chVTGetSystemTime();
|
||||||
|
usbDbgPrintf("FS: Read 1MB in %d ms, %dkB/s",
|
||||||
|
et - st,
|
||||||
|
(1024UL*1000) / (et - st));
|
||||||
|
f_close(&file);
|
||||||
|
}
|
||||||
|
|
||||||
|
//scan files test
|
||||||
|
if (1) {
|
||||||
|
usbDbgPuts("FS: Scan files test");
|
||||||
|
fbuff[0] = 0;
|
||||||
|
scan_files(chp, (char *)fbuff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usbDbgPuts("FS: Tests done, restarting in 3s");
|
||||||
|
chThdSleepMilliseconds(3000);
|
||||||
|
|
||||||
|
goto start;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
|
||||||
|
halInit();
|
||||||
|
usbhInit();
|
||||||
|
chSysInit();
|
||||||
|
|
||||||
|
//PA2(TX) and PA3(RX) are routed to USART2
|
||||||
|
sdStart(&SD2, NULL);
|
||||||
|
palSetPadMode(GPIOA, 2, PAL_MODE_ALTERNATE(7));
|
||||||
|
palSetPadMode(GPIOA, 3, PAL_MODE_ALTERNATE(7));
|
||||||
|
|
||||||
|
#if STM32_USBH_USE_OTG1
|
||||||
|
//VBUS - configured in board.h
|
||||||
|
//USB_FS - configured in board.h
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if STM32_USBH_USE_OTG2
|
||||||
|
//USB_HS
|
||||||
|
//TODO: Initialize Pads
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAL_USBH_USE_MSD
|
||||||
|
usbhmsdObjectInit(&USBHMSD[0]);
|
||||||
|
usbhmsdLUNObjectInit(&MSBLKD[0]);
|
||||||
|
chThdCreateStatic(waTestMSD, sizeof(waTestMSD), NORMALPRIO, ThreadTestMSD, 0);
|
||||||
|
#endif
|
||||||
|
#if HAL_USBH_USE_FTDI
|
||||||
|
usbhftdiObjectInit(&USBHFTDID[0]);
|
||||||
|
usbhftdipObjectInit(&FTDIPD[0]);
|
||||||
|
chThdCreateStatic(waTestFTDI, sizeof(waTestFTDI), NORMALPRIO, ThreadTestFTDI, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//turn on USB power
|
||||||
|
palClearPad(GPIOC, GPIOC_OTG_FS_POWER_ON);
|
||||||
|
|
||||||
|
//start
|
||||||
|
#if STM32_USBH_USE_OTG1
|
||||||
|
usbhStart(&USBHD1);
|
||||||
|
#endif
|
||||||
|
#if STM32_USBH_USE_OTG2
|
||||||
|
usbhStart(&USBHD2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
#if STM32_USBH_USE_OTG1
|
||||||
|
usbhMainLoop(&USBHD1);
|
||||||
|
#endif
|
||||||
|
#if STM32_USBH_USE_OTG2
|
||||||
|
usbhMainLoop(&USBHD2);
|
||||||
|
#endif
|
||||||
|
chThdSleepMilliseconds(100);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,324 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MCUCONF_H_
|
||||||
|
#define _MCUCONF_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* STM32F4xx drivers configuration.
|
||||||
|
* The following settings override the default settings present in
|
||||||
|
* the various device driver implementation headers.
|
||||||
|
* Note that the settings for each driver only have effect if the whole
|
||||||
|
* driver is enabled in halconf.h.
|
||||||
|
*
|
||||||
|
* IRQ priorities:
|
||||||
|
* 15...0 Lowest...Highest.
|
||||||
|
*
|
||||||
|
* DMA priorities:
|
||||||
|
* 0...3 Lowest...Highest.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define STM32F4xx_MCUCONF
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HAL driver system settings.
|
||||||
|
*/
|
||||||
|
#define STM32_NO_INIT FALSE
|
||||||
|
#define STM32_HSI_ENABLED TRUE
|
||||||
|
#define STM32_LSI_ENABLED TRUE
|
||||||
|
#define STM32_HSE_ENABLED TRUE
|
||||||
|
#define STM32_LSE_ENABLED FALSE
|
||||||
|
#define STM32_CLOCK48_REQUIRED TRUE
|
||||||
|
#define STM32_SW STM32_SW_PLL
|
||||||
|
#define STM32_PLLSRC STM32_PLLSRC_HSE
|
||||||
|
#define STM32_PLLM_VALUE 8
|
||||||
|
#define STM32_PLLN_VALUE 336
|
||||||
|
#define STM32_PLLP_VALUE 2
|
||||||
|
#define STM32_PLLQ_VALUE 7
|
||||||
|
#define STM32_HPRE STM32_HPRE_DIV1
|
||||||
|
#define STM32_PPRE1 STM32_PPRE1_DIV4
|
||||||
|
#define STM32_PPRE2 STM32_PPRE2_DIV2
|
||||||
|
#define STM32_RTCSEL STM32_RTCSEL_LSI
|
||||||
|
#define STM32_RTCPRE_VALUE 8
|
||||||
|
#define STM32_MCO1SEL STM32_MCO1SEL_HSI
|
||||||
|
#define STM32_MCO1PRE STM32_MCO1PRE_DIV1
|
||||||
|
#define STM32_MCO2SEL STM32_MCO2SEL_SYSCLK
|
||||||
|
#define STM32_MCO2PRE STM32_MCO2PRE_DIV5
|
||||||
|
#define STM32_I2SSRC STM32_I2SSRC_CKIN
|
||||||
|
#define STM32_PLLI2SN_VALUE 192
|
||||||
|
#define STM32_PLLI2SR_VALUE 5
|
||||||
|
#define STM32_PVD_ENABLE FALSE
|
||||||
|
#define STM32_PLS STM32_PLS_LEV0
|
||||||
|
#define STM32_BKPRAM_ENABLE FALSE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ADC driver system settings.
|
||||||
|
*/
|
||||||
|
#define STM32_ADC_ADCPRE ADC_CCR_ADCPRE_DIV4
|
||||||
|
#define STM32_ADC_USE_ADC1 FALSE
|
||||||
|
#define STM32_ADC_USE_ADC2 FALSE
|
||||||
|
#define STM32_ADC_USE_ADC3 FALSE
|
||||||
|
#define STM32_ADC_ADC1_DMA_STREAM STM32_DMA_STREAM_ID(2, 4)
|
||||||
|
#define STM32_ADC_ADC2_DMA_STREAM STM32_DMA_STREAM_ID(2, 2)
|
||||||
|
#define STM32_ADC_ADC3_DMA_STREAM STM32_DMA_STREAM_ID(2, 1)
|
||||||
|
#define STM32_ADC_ADC1_DMA_PRIORITY 2
|
||||||
|
#define STM32_ADC_ADC2_DMA_PRIORITY 2
|
||||||
|
#define STM32_ADC_ADC3_DMA_PRIORITY 2
|
||||||
|
#define STM32_ADC_IRQ_PRIORITY 6
|
||||||
|
#define STM32_ADC_ADC1_DMA_IRQ_PRIORITY 6
|
||||||
|
#define STM32_ADC_ADC2_DMA_IRQ_PRIORITY 6
|
||||||
|
#define STM32_ADC_ADC3_DMA_IRQ_PRIORITY 6
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CAN driver system settings.
|
||||||
|
*/
|
||||||
|
#define STM32_CAN_USE_CAN1 FALSE
|
||||||
|
#define STM32_CAN_USE_CAN2 FALSE
|
||||||
|
#define STM32_CAN_CAN1_IRQ_PRIORITY 11
|
||||||
|
#define STM32_CAN_CAN2_IRQ_PRIORITY 11
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DAC driver system settings.
|
||||||
|
*/
|
||||||
|
#define STM32_DAC_DUAL_MODE FALSE
|
||||||
|
#define STM32_DAC_USE_DAC1_CH1 FALSE
|
||||||
|
#define STM32_DAC_USE_DAC1_CH2 FALSE
|
||||||
|
#define STM32_DAC_DAC1_CH1_IRQ_PRIORITY 10
|
||||||
|
#define STM32_DAC_DAC1_CH2_IRQ_PRIORITY 10
|
||||||
|
#define STM32_DAC_DAC1_CH1_DMA_PRIORITY 2
|
||||||
|
#define STM32_DAC_DAC1_CH2_DMA_PRIORITY 2
|
||||||
|
#define STM32_DAC_DAC1_CH1_DMA_STREAM STM32_DMA_STREAM_ID(1, 5)
|
||||||
|
#define STM32_DAC_DAC1_CH2_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EXT driver system settings.
|
||||||
|
*/
|
||||||
|
#define STM32_EXT_EXTI0_IRQ_PRIORITY 6
|
||||||
|
#define STM32_EXT_EXTI1_IRQ_PRIORITY 6
|
||||||
|
#define STM32_EXT_EXTI2_IRQ_PRIORITY 6
|
||||||
|
#define STM32_EXT_EXTI3_IRQ_PRIORITY 6
|
||||||
|
#define STM32_EXT_EXTI4_IRQ_PRIORITY 6
|
||||||
|
#define STM32_EXT_EXTI5_9_IRQ_PRIORITY 6
|
||||||
|
#define STM32_EXT_EXTI10_15_IRQ_PRIORITY 6
|
||||||
|
#define STM32_EXT_EXTI16_IRQ_PRIORITY 6
|
||||||
|
#define STM32_EXT_EXTI17_IRQ_PRIORITY 15
|
||||||
|
#define STM32_EXT_EXTI18_IRQ_PRIORITY 6
|
||||||
|
#define STM32_EXT_EXTI19_IRQ_PRIORITY 6
|
||||||
|
#define STM32_EXT_EXTI20_IRQ_PRIORITY 6
|
||||||
|
#define STM32_EXT_EXTI21_IRQ_PRIORITY 15
|
||||||
|
#define STM32_EXT_EXTI22_IRQ_PRIORITY 15
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GPT driver system settings.
|
||||||
|
*/
|
||||||
|
#define STM32_GPT_USE_TIM1 FALSE
|
||||||
|
#define STM32_GPT_USE_TIM2 FALSE
|
||||||
|
#define STM32_GPT_USE_TIM3 FALSE
|
||||||
|
#define STM32_GPT_USE_TIM4 FALSE
|
||||||
|
#define STM32_GPT_USE_TIM5 FALSE
|
||||||
|
#define STM32_GPT_USE_TIM6 FALSE
|
||||||
|
#define STM32_GPT_USE_TIM7 FALSE
|
||||||
|
#define STM32_GPT_USE_TIM8 FALSE
|
||||||
|
#define STM32_GPT_USE_TIM9 FALSE
|
||||||
|
#define STM32_GPT_USE_TIM11 FALSE
|
||||||
|
#define STM32_GPT_USE_TIM12 FALSE
|
||||||
|
#define STM32_GPT_USE_TIM14 FALSE
|
||||||
|
#define STM32_GPT_TIM1_IRQ_PRIORITY 7
|
||||||
|
#define STM32_GPT_TIM2_IRQ_PRIORITY 7
|
||||||
|
#define STM32_GPT_TIM3_IRQ_PRIORITY 7
|
||||||
|
#define STM32_GPT_TIM4_IRQ_PRIORITY 7
|
||||||
|
#define STM32_GPT_TIM5_IRQ_PRIORITY 7
|
||||||
|
#define STM32_GPT_TIM6_IRQ_PRIORITY 7
|
||||||
|
#define STM32_GPT_TIM7_IRQ_PRIORITY 7
|
||||||
|
#define STM32_GPT_TIM8_IRQ_PRIORITY 7
|
||||||
|
#define STM32_GPT_TIM9_IRQ_PRIORITY 7
|
||||||
|
#define STM32_GPT_TIM11_IRQ_PRIORITY 7
|
||||||
|
#define STM32_GPT_TIM12_IRQ_PRIORITY 7
|
||||||
|
#define STM32_GPT_TIM14_IRQ_PRIORITY 7
|
||||||
|
|
||||||
|
/*
|
||||||
|
* I2C driver system settings.
|
||||||
|
*/
|
||||||
|
#define STM32_I2C_USE_I2C1 FALSE
|
||||||
|
#define STM32_I2C_USE_I2C2 FALSE
|
||||||
|
#define STM32_I2C_USE_I2C3 FALSE
|
||||||
|
#define STM32_I2C_BUSY_TIMEOUT 50
|
||||||
|
#define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
|
||||||
|
#define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
|
||||||
|
#define STM32_I2C_I2C2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
|
||||||
|
#define STM32_I2C_I2C2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
|
||||||
|
#define STM32_I2C_I2C3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
|
||||||
|
#define STM32_I2C_I2C3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
|
||||||
|
#define STM32_I2C_I2C1_IRQ_PRIORITY 5
|
||||||
|
#define STM32_I2C_I2C2_IRQ_PRIORITY 5
|
||||||
|
#define STM32_I2C_I2C3_IRQ_PRIORITY 5
|
||||||
|
#define STM32_I2C_I2C1_DMA_PRIORITY 3
|
||||||
|
#define STM32_I2C_I2C2_DMA_PRIORITY 3
|
||||||
|
#define STM32_I2C_I2C3_DMA_PRIORITY 3
|
||||||
|
#define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure")
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ICU driver system settings.
|
||||||
|
*/
|
||||||
|
#define STM32_ICU_USE_TIM1 FALSE
|
||||||
|
#define STM32_ICU_USE_TIM2 FALSE
|
||||||
|
#define STM32_ICU_USE_TIM3 FALSE
|
||||||
|
#define STM32_ICU_USE_TIM4 FALSE
|
||||||
|
#define STM32_ICU_USE_TIM5 FALSE
|
||||||
|
#define STM32_ICU_USE_TIM8 FALSE
|
||||||
|
#define STM32_ICU_USE_TIM9 FALSE
|
||||||
|
#define STM32_ICU_TIM1_IRQ_PRIORITY 7
|
||||||
|
#define STM32_ICU_TIM2_IRQ_PRIORITY 7
|
||||||
|
#define STM32_ICU_TIM3_IRQ_PRIORITY 7
|
||||||
|
#define STM32_ICU_TIM4_IRQ_PRIORITY 7
|
||||||
|
#define STM32_ICU_TIM5_IRQ_PRIORITY 7
|
||||||
|
#define STM32_ICU_TIM8_IRQ_PRIORITY 7
|
||||||
|
#define STM32_ICU_TIM9_IRQ_PRIORITY 7
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MAC driver system settings.
|
||||||
|
*/
|
||||||
|
#define STM32_MAC_TRANSMIT_BUFFERS 2
|
||||||
|
#define STM32_MAC_RECEIVE_BUFFERS 4
|
||||||
|
#define STM32_MAC_BUFFERS_SIZE 1522
|
||||||
|
#define STM32_MAC_PHY_TIMEOUT 100
|
||||||
|
#define STM32_MAC_ETH1_CHANGE_PHY_STATE TRUE
|
||||||
|
#define STM32_MAC_ETH1_IRQ_PRIORITY 13
|
||||||
|
#define STM32_MAC_IP_CHECKSUM_OFFLOAD 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PWM driver system settings.
|
||||||
|
*/
|
||||||
|
#define STM32_PWM_USE_ADVANCED FALSE
|
||||||
|
#define STM32_PWM_USE_TIM1 FALSE
|
||||||
|
#define STM32_PWM_USE_TIM2 FALSE
|
||||||
|
#define STM32_PWM_USE_TIM3 FALSE
|
||||||
|
#define STM32_PWM_USE_TIM4 FALSE
|
||||||
|
#define STM32_PWM_USE_TIM5 FALSE
|
||||||
|
#define STM32_PWM_USE_TIM8 FALSE
|
||||||
|
#define STM32_PWM_USE_TIM9 FALSE
|
||||||
|
#define STM32_PWM_TIM1_IRQ_PRIORITY 7
|
||||||
|
#define STM32_PWM_TIM2_IRQ_PRIORITY 7
|
||||||
|
#define STM32_PWM_TIM3_IRQ_PRIORITY 7
|
||||||
|
#define STM32_PWM_TIM4_IRQ_PRIORITY 7
|
||||||
|
#define STM32_PWM_TIM5_IRQ_PRIORITY 7
|
||||||
|
#define STM32_PWM_TIM8_IRQ_PRIORITY 7
|
||||||
|
#define STM32_PWM_TIM9_IRQ_PRIORITY 7
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SDC driver system settings.
|
||||||
|
*/
|
||||||
|
#define STM32_SDC_SDIO_DMA_PRIORITY 3
|
||||||
|
#define STM32_SDC_SDIO_IRQ_PRIORITY 9
|
||||||
|
#define STM32_SDC_WRITE_TIMEOUT_MS 250
|
||||||
|
#define STM32_SDC_READ_TIMEOUT_MS 25
|
||||||
|
#define STM32_SDC_CLOCK_ACTIVATION_DELAY 10
|
||||||
|
#define STM32_SDC_SDIO_UNALIGNED_SUPPORT TRUE
|
||||||
|
#define STM32_SDC_SDIO_DMA_STREAM STM32_DMA_STREAM_ID(2, 3)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SERIAL driver system settings.
|
||||||
|
*/
|
||||||
|
#define STM32_SERIAL_USE_USART1 FALSE
|
||||||
|
#define STM32_SERIAL_USE_USART2 TRUE
|
||||||
|
#define STM32_SERIAL_USE_USART3 FALSE
|
||||||
|
#define STM32_SERIAL_USE_UART4 FALSE
|
||||||
|
#define STM32_SERIAL_USE_UART5 FALSE
|
||||||
|
#define STM32_SERIAL_USE_USART6 FALSE
|
||||||
|
#define STM32_SERIAL_USART1_PRIORITY 12
|
||||||
|
#define STM32_SERIAL_USART2_PRIORITY 12
|
||||||
|
#define STM32_SERIAL_USART3_PRIORITY 12
|
||||||
|
#define STM32_SERIAL_UART4_PRIORITY 12
|
||||||
|
#define STM32_SERIAL_UART5_PRIORITY 12
|
||||||
|
#define STM32_SERIAL_USART6_PRIORITY 12
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SPI driver system settings.
|
||||||
|
*/
|
||||||
|
#define STM32_SPI_USE_SPI1 FALSE
|
||||||
|
#define STM32_SPI_USE_SPI2 FALSE
|
||||||
|
#define STM32_SPI_USE_SPI3 FALSE
|
||||||
|
#define STM32_SPI_SPI1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 0)
|
||||||
|
#define STM32_SPI_SPI1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 3)
|
||||||
|
#define STM32_SPI_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3)
|
||||||
|
#define STM32_SPI_SPI2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
|
||||||
|
#define STM32_SPI_SPI3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
|
||||||
|
#define STM32_SPI_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
|
||||||
|
#define STM32_SPI_SPI1_DMA_PRIORITY 1
|
||||||
|
#define STM32_SPI_SPI2_DMA_PRIORITY 1
|
||||||
|
#define STM32_SPI_SPI3_DMA_PRIORITY 1
|
||||||
|
#define STM32_SPI_SPI1_IRQ_PRIORITY 10
|
||||||
|
#define STM32_SPI_SPI2_IRQ_PRIORITY 10
|
||||||
|
#define STM32_SPI_SPI3_IRQ_PRIORITY 10
|
||||||
|
#define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure")
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ST driver system settings.
|
||||||
|
*/
|
||||||
|
#define STM32_ST_IRQ_PRIORITY 8
|
||||||
|
#define STM32_ST_USE_TIMER 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* UART driver system settings.
|
||||||
|
*/
|
||||||
|
#define STM32_UART_USE_USART1 FALSE
|
||||||
|
#define STM32_UART_USE_USART2 FALSE
|
||||||
|
#define STM32_UART_USE_USART3 FALSE
|
||||||
|
#define STM32_UART_USE_UART4 FALSE
|
||||||
|
#define STM32_UART_USE_UART5 FALSE
|
||||||
|
#define STM32_UART_USE_USART6 FALSE
|
||||||
|
#define STM32_UART_USART1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 5)
|
||||||
|
#define STM32_UART_USART1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
|
||||||
|
#define STM32_UART_USART2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 5)
|
||||||
|
#define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
|
||||||
|
#define STM32_UART_USART3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 1)
|
||||||
|
#define STM32_UART_USART3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3)
|
||||||
|
#define STM32_UART_UART4_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
|
||||||
|
#define STM32_UART_UART4_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
|
||||||
|
#define STM32_UART_UART5_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
|
||||||
|
#define STM32_UART_UART5_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
|
||||||
|
#define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2)
|
||||||
|
#define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
|
||||||
|
#define STM32_UART_USART1_IRQ_PRIORITY 12
|
||||||
|
#define STM32_UART_USART2_IRQ_PRIORITY 12
|
||||||
|
#define STM32_UART_USART3_IRQ_PRIORITY 12
|
||||||
|
#define STM32_UART_UART4_IRQ_PRIORITY 12
|
||||||
|
#define STM32_UART_UART5_IRQ_PRIORITY 12
|
||||||
|
#define STM32_UART_USART6_IRQ_PRIORITY 12
|
||||||
|
#define STM32_UART_USART1_DMA_PRIORITY 0
|
||||||
|
#define STM32_UART_USART2_DMA_PRIORITY 0
|
||||||
|
#define STM32_UART_USART3_DMA_PRIORITY 0
|
||||||
|
#define STM32_UART_UART4_DMA_PRIORITY 0
|
||||||
|
#define STM32_UART_UART5_DMA_PRIORITY 0
|
||||||
|
#define STM32_UART_USART6_DMA_PRIORITY 0
|
||||||
|
#define STM32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure")
|
||||||
|
|
||||||
|
/*
|
||||||
|
* USB driver system settings.
|
||||||
|
*/
|
||||||
|
#define STM32_USB_USE_OTG1 FALSE
|
||||||
|
#define STM32_USB_USE_OTG2 FALSE
|
||||||
|
#define STM32_USB_OTG1_IRQ_PRIORITY 14
|
||||||
|
#define STM32_USB_OTG2_IRQ_PRIORITY 14
|
||||||
|
#define STM32_USB_OTG1_RX_FIFO_SIZE 512
|
||||||
|
#define STM32_USB_OTG2_RX_FIFO_SIZE 1024
|
||||||
|
#define STM32_USB_OTG_THREAD_PRIO LOWPRIO
|
||||||
|
#define STM32_USB_OTG_THREAD_STACK_SIZE 128
|
||||||
|
#define STM32_USB_OTGFIFO_FILL_BASEPRI 0
|
||||||
|
|
||||||
|
#include "mcuconf_community.h"
|
||||||
|
|
||||||
|
#endif /* _MCUCONF_H_ */
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2014 Uladzimir Pylinsky aka barthess
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FSMC driver system settings.
|
||||||
|
*/
|
||||||
|
#define STM32_FSMC_USE_FSMC1 FALSE
|
||||||
|
#define STM32_FSMC_FSMC1_IRQ_PRIORITY 10
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FSMC NAND driver system settings.
|
||||||
|
*/
|
||||||
|
#define STM32_NAND_USE_FSMC_NAND1 FALSE
|
||||||
|
#define STM32_NAND_USE_FSMC_NAND2 FALSE
|
||||||
|
#define STM32_NAND_USE_EXT_INT FALSE
|
||||||
|
#define STM32_NAND_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
|
||||||
|
#define STM32_NAND_DMA_PRIORITY 0
|
||||||
|
#define STM32_NAND_DMA_ERROR_HOOK(nandp) osalSysHalt("DMA failure")
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FSMC SRAM driver system settings.
|
||||||
|
*/
|
||||||
|
#define STM32_USE_FSMC_SRAM FALSE
|
||||||
|
#define STM32_SRAM_USE_FSMC_SRAM1 FALSE
|
||||||
|
#define STM32_SRAM_USE_FSMC_SRAM2 FALSE
|
||||||
|
#define STM32_SRAM_USE_FSMC_SRAM3 FLASE
|
||||||
|
#define STM32_SRAM_USE_FSMC_SRAM4 FALSE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FSMC SDRAM driver system settings.
|
||||||
|
*/
|
||||||
|
#define STM32_USE_FSMC_SDRAM FALSE
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* USBH driver system settings.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define STM32_OTG1_CHANNELS_NUMBER 8
|
||||||
|
#define STM32_OTG2_CHANNELS_NUMBER 12
|
||||||
|
|
||||||
|
#define STM32_USBH_USE_OTG1 1
|
||||||
|
#define STM32_OTG1_RXFIFO_SIZE 1024
|
||||||
|
#define STM32_OTG1_PTXFIFO_SIZE 128
|
||||||
|
#define STM32_OTG1_NPTXFIFO_SIZE 128
|
||||||
|
|
||||||
|
#define STM32_USBH_USE_OTG2 0
|
||||||
|
#define STM32_OTG2_RXFIFO_SIZE 2048
|
||||||
|
#define STM32_OTG2_PTXFIFO_SIZE 1024
|
||||||
|
#define STM32_OTG2_NPTXFIFO_SIZE 1024
|
||||||
|
|
||||||
|
#define STM32_USBH_MIN_QSPACE 4
|
||||||
|
#define STM32_USBH_CHANNELS_NP 4
|
|
@ -0,0 +1,25 @@
|
||||||
|
*****************************************************************************
|
||||||
|
** ChibiOS/RT port for ARM-Cortex-M4 STM32F407. **
|
||||||
|
*****************************************************************************
|
||||||
|
|
||||||
|
** TARGET **
|
||||||
|
|
||||||
|
The demo runs on an ST STM32F4-Discovery board.
|
||||||
|
|
||||||
|
** The Demo **
|
||||||
|
|
||||||
|
|
||||||
|
** Build Procedure **
|
||||||
|
|
||||||
|
The demo has been tested by using the free Codesourcery GCC-based toolchain
|
||||||
|
and YAGARTO. just modify the TRGT line in the makefile in order to use
|
||||||
|
different GCC toolchains.
|
||||||
|
|
||||||
|
** Notes **
|
||||||
|
|
||||||
|
Some files used by the demo are not part of ChibiOS/RT but are copyright of
|
||||||
|
ST Microelectronics and are licensed under a different license.
|
||||||
|
Also note that not all the files present in the ST library are distributed
|
||||||
|
with ChibiOS/RT, you can find the whole library on the ST web site:
|
||||||
|
|
||||||
|
http://www.st.com
|
Loading…
Reference in New Issue