USB-Host: Initial commit

This commit is contained in:
Fabien Poussin 2016-02-15 23:34:25 +01:00
parent 1548bca80f
commit 771feb098d
37 changed files with 16355 additions and 1 deletions

View File

@ -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/onewire.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

View File

@ -32,6 +32,7 @@
/* Normal drivers.*/
#include "nand.h"
#include "eicu.h"
#include "usbh.h"
/* Complex drivers.*/
#include "onewire.h"

439
os/hal/include/usbh.h Normal file
View File

@ -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_ */

View File

@ -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_ */

160
os/hal/include/usbh/defs.h Normal file
View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

598
os/hal/include/usbh/list.h Normal file
View File

@ -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_ */

View File

@ -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

View File

@ -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_ */

View File

@ -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/LTDCv1/stm32_ltdc.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
PLATFORMINC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/DMA2Dv1 \
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/FSMCv1 \
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/LTDCv1 \
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1 \
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/USBHv1 \
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD

View File

@ -64,6 +64,10 @@ void halCommunityInit(void) {
#if HAL_USE_CRC || defined(__DOXYGEN__)
crcInit();
#endif
#if HAL_USE_USBH || defined(__DOXYGEN__)
usbhInit();
#endif
}
#endif /* HAL_USE_COMMUNITY */

1395
os/hal/src/usbh.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

717
os/hal/src/usbh/usbh_ftdi.c Normal file
View File

@ -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

302
os/hal/src/usbh/usbh_hub.c Normal file
View File

@ -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

939
os/hal/src/usbh/usbh_msd.c Normal file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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_ */
/** @} */

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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
*/

View File

@ -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_ */
/** @} */

View File

@ -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_ */
/** @} */

View File

@ -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

View File

@ -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);
}
}

View File

@ -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_ */

View File

@ -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

View File

@ -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