vxkernel - v0.7.0-4 : add USB request handling (WIP)

*add*
> [vhex/display]
  | [text] add va_list version of dtext() and dprint()
> [vhex/defs]
  | [types] add x_union_alone
> [vhex/usb]
  | [request] add USB request (WIP)
  | [pipe] add USB pipe API (WIP)
  | [dcp] add USB DCP API (WIP)
  | [macros] add interrupt clearing helper
  | [descriptor] add main USB descriptors

*update*
> [vhex/defs]
  | [attributes] rename VPACKEDENUM -> VPACKED_ALONE
> [vhex/usb]
  | [interrupt] enable setup interruptions
  | [open] perform USB device configuration check

*fix*
> [vhex/defs]
  | [call] fix last argument injection
> [vhex/usb]
  | [macros] fix delay for register sync.
  | [open] force-clear interrupt flags befor enabling interruption
This commit is contained in:
Yann MAGNIN 2023-01-27 16:21:44 +01:00
parent 42c3fabb34
commit c6aa4b5ac4
19 changed files with 857 additions and 23 deletions

View File

@ -20,7 +20,7 @@
access sizes silently fail - honestly you don't want this to happen */
#define VPACKED(x) __attribute__((packed, aligned(x)))
/* Packed enumerations */
#define VPACKEDENUM __attribute__((packed))
#define VPACKED_ALONE __attribute__((packed))
/* Transparent unions */
#define VTRANSPARENT __attribute__((transparent_union))

View File

@ -60,7 +60,7 @@ typedef struct vhex_call vhex_call_t;
/* VHEX_CALL(): Build an callback from function and arguments */
#define VHEX_CALL(fct, ...) \
((vhex_call_t){ \
((vhex_call_t){ \
.function = (void*)fct, \
.args = { __VA_OPT__(VHEX_CALL_ARGS1(__VA_ARGS__)) } \
})
@ -78,7 +78,7 @@ typedef struct vhex_call vhex_call_t;
"VHEX_CALL: too many arguments (maximum 4)" \
); \
) \
(vhex_call_arg_t)(a4); \
VHEX_CALL_ARG(a4) \
})
#ifdef __cplusplus

View File

@ -45,4 +45,26 @@ typedef unsigned int uint;
struct { fields } VPACKED(4); \
} VPACKED(4) name
/* byte_union() - same as `byte_union()` but without aligment */
#define byte_union_alone(name, fields) \
union { \
uint8_t byte; \
struct { fields } VPACKED_ALONE;\
} VPACKED_ALONE name
/* word_union_alone() - same as `word_union()` but without aligment */
#define word_union_alone(name, fields) \
union { \
uint16_t word; \
struct { fields } VPACKED_ALONE;\
} VPACKED_ALONE name
/* lword_union_alone() - same as `lword_union()` but without aligment */
#define lword_union_alone(name, fields) \
union { \
uint32_t lword; \
struct { fields } VPACKED_ALONE;\
} VPACKED_ALONE name
#endif /*__VHEX_DEFS_TYPES__*/

View File

@ -34,10 +34,25 @@ extern did_t dprint_opt(
int x, int y,
int fg, int bg,
int align,
char const * const str, ...
char const * const str,
...
);
/* dprint() : display formated text */
extern did_t dprint(int x, int y, int fg, char const * const text, ...);
#include <stdarg.h>
/* dvprint_opt(): Display a string of text */
extern did_t dvprint_opt(
int x, int y,
int fg, int bg,
int align,
char const *text,
va_list ap
);
/* dvprint() : display formated text (vargs version) */
extern did_t dvprint(int x, int y, int fg, char const * const text, va_list ap);
#endif /* __VHEX_DISPLAY_TEXT_RENDER__ */

View File

@ -433,6 +433,25 @@ union __sh7305_usb_uponcr
// Kernel-level USB API
//---
/* SH7305_USB_DVSQ_* - device state value */
enum {
SH7305_USB_DVSQ_POWERED = 0,
SH7305_USB_DVSQ_DEFAULT = 1,
SH7305_USB_DVSQ_ADDRESS = 2,
SH7305_USB_DVSQ_CONFIGURED = 3,
};
/* SH&SH7305_USB_REQT_* - device request value */
enum {
SH7305_USB_REQT_GET_STATUS = 0x00,
SH7305_USB_REQT_CLEAR_FEATURE = 0x01,
SH7305_USB_REQT_SET_FEATURE = 0x03,
SH7305_USB_REQT_SET_ADDRESS = 0x05,
SH7305_USB_REQT_GET_DESCRIPTOR = 0x06,
SH7305_USB_REQT_SET_DESCRIPTOR = 0x07,
SH7305_USB_REQT_GET_CONFIGURATION = 0x08,
SH7305_USB_REQT_SET_CONFIGURATION = 0x09,
};
/* sh7305_usb_hpowered() : check if the USB module is powered */
extern bool sh7305_usb_hpowered(void);
@ -442,24 +461,40 @@ extern int sh7305_usb_hpoweron(void);
/* sh7305_usb_hpoweroff() : power off the USB module */
extern int sh7305_usb_hpoweroff(void);
/* sh7305_usb_open() : power on the module and setup USB module */
extern int sh7305_usb_open(void *_, void *__);
/* sh7305_usb_interrupt_handler() : interrupt handler invoked by hardware */
extern void sh7305_usb_interrupt_handler(void);
/* sh7305_usb_request_handle() : handle USB request */
extern void sh7305_usb_request_handle(void);
#include <vhex/usb/device.h>
/* sh7305_usb_open() : power on the module and setup USB module */
extern int sh7305_usb_open(struct usb_full_device *device);
/* sh7305_configuration_resolve() : check and resolve USB configuration */
extern int sh7305_usb_configuration_resolve(struct usb_full_device *device);
/* sh7305_pipe_find() : try to find a pipe */
extern int sh7305_usb_pipe_find(int type);
/* sh7305_usb_dcp_write() : send data through DCP pipe */
extern int sh7305_usb_dcp_write(void *buffer, size_t n);
//---
// Utils
//---
#include <vhex/driver/mpu/sh/sh7305/tmu.h>
#include <vhex/usb/logger.h>
#include <vhex/defs/call.h>
/* SH7305_USB_REG_SYN() : activly wait the condition. */
#define SH7305_USB_REG_SYNC(condition) ({ \
volatile int __trigger = 0; \
int __timer = sh7305_tmu_configure( \
1000000000 /*µs*/, \
100000 /*µs*/, \
VHEX_CALL_SET_STOP(&__trigger) \
); \
if(__timer >= 0) { timer_start(__timer); } \
@ -476,4 +511,12 @@ extern void sh7305_usb_interrupt_handler(void);
} \
})
/* SH7305_USB_INTSTS0_CLEAR() : clear interrup flags */
#define SH7305_USB_INTSTS0_CLEAR(field_name) ({ \
__typeof__(SH7305_USB.INTSTS0) __intsts0 = { .word = 0xffff }; \
__intsts0.field_name = 0; \
do SH7305_USB.INTSTS0 = __intsts0; \
while(SH7305_USB.INTSTS0.field_name != 0); \
})
#endif /*__VHEX_MPU_SH7305_USB_ */

View File

@ -0,0 +1,49 @@
#ifndef __VHEX_USB_DESCRIPTOR_CONFIGURATION_H__
#define __VHEX_USB_DESCRIPTOR_CONFIGURATION_H__ 1
#include <vhex/defs/types.h>
/* usb_descriptor_configuration - USB Configuration Descriptor struct */
struct usb_descriptor_configuration {
uint8_t bLengh; /* size of this descriptor in bytes */
uint8_t bDescriptorType; /* USB_DESCRIPTOR_CONFIG */
uint16_t wTotalLengh; /* total lengh of configuration data */
uint8_t bNumInterfaces; /* number of interface */
uint8_t bConfigurationValue; /* configuration index (start at 1!) */
uint8_t iConfiguration; /* index of string desc. */
/* Configuration characteristics
* @notes
* - power 1=self-powered
* - wakeup 1=remote wakeup support */
byte_union_alone(bmAttributes,
uint8_t : 1;
uint8_t power : 1;
uint8_t wakeup : 1;
uint8_t : 4;
);
/* Maximum power that USB should provide
* @notes
* - only provided if bmAttributes.power=1
* - exposed as bMaxPower=1 -> 2mA (ex: bMaxPower=50 -> 100mA) */
uint8_t bMaxPower;
} VPACKED_ALONE;
#include <vhex/usb/descriptor/types.h>
#include <vhex/usb/utils.h>
/* USB_DECLARE_DESC_CONF - helper to declare configuration descriptor */
#define USB_DECLARE_DESC_CONF(name, ...) \
struct usb_descriptor_configuration name = \
USB_DECLARE_DESC_CONF_RAW(__VA_ARGS__)
/* USB_DECLARE_DESC_CONF_RAW - helper to declare default content */
#define USB_DECLARE_DESC_CONF_RAW(...) \
{ \
.bLengh = sizeof(struct usb_descriptor_configuration), \
.bDescriptorType = USB_DESCRIPTOR_CONFIGURATION, \
__VA_ARGS__ \
}
#endif /* __VHEX_USB_DESCRIPTOR_CONFIGURATION_H__ */

View File

@ -0,0 +1,41 @@
#ifndef __VHEX_USB_DESCRIPTOR_DEVICE_H__
#define __VHEX_USB_DESCRIPTOR_DEVICE_H__ 1
#include <vhex/defs/types.h>
/* usb_descriptor_device - USB Device Descriptor struct */
struct usb_descriptor_device {
uint8_t bLengh; /* size of this descriptor in bytes */
uint8_t bDescriptorType; /* descriptor type (USB_DESCRIPTOR_DEVICE) */
uint16_t bcdUSB; /* USB release number in bin. (0x210 -> 2.1) */
uint8_t bDeviceClass; /* class code */
uint8_t bDeviceSubClass; /* subclass code */
uint8_t bDeviceProtocol; /* protocol code */
uint8_t bMaxPacketSize0; /* packet size of endpoint 0 */
uint16_t idVendor; /* vendor ID (assigned by USB-IF) */
uint16_t idProduct; /* product ID (assigned by manufacturer) */
uint16_t bcdDevice; /* device release version (0x220 -> 2.220) */
uint8_t iManufacturer; /* index of string descr. for Manufacturer */
uint8_t iProduct; /* index of string descr. for product */
uint8_t iSerialNumber; /* index of string descr. for serial number */
uint8_t bNumConfigurations;/* number of possible configuration */
} VPACKED_ALONE;
#include <vhex/usb/descriptor/types.h>
#include <vhex/usb/utils.h>
/* USB_DECLARE_DESC_DEV - helper to declare device descriptor */
#define USB_DECLARE_DESC_DEVICE(name, ...) \
struct usb_descriptor_device name = \
USB_DECLARE_DESC_DEVICE_RAW(__VA_ARGS__)
/* USB_DECLARE_DESC_DEVICE_RAW - helper to declare default content */
#define USB_DECLARE_DESC_DEVICE_RAW(...) \
{ \
.bLengh = sizeof(struct usb_descriptor_device), \
.bDescriptorType = USB_DESCRIPTOR_DEVICE, \
.bcdUSB = USB_WORD_TO(0x200), \
__VA_ARGS__ \
}
#endif /* __VHEX_USB_DESCRIPTOR_DEVICE_H__ */

View File

@ -0,0 +1,62 @@
#ifndef __VHEX_USB_DESCRIPTOR_ENDPOINT_H__
#define __VHEX_USB_DESCRIPTOR_ENDPOINT_H__ 1
#include <vhex/defs/types.h>
/* usb_descriptor_endpoint - USB Endpoint Descriptor struct */
struct usb_descriptor_endpoint {
uint8_t bLengh; /* size of this descriptor in bytes */
uint8_t bDescriptorType; /* descriptor type (USB_DESCRIPTOR_DEVICE) */
/* bEndpointAddress - Endpoint address configuration
* @notes
* - dir 0=OUT, 1=IN
* - number the endpoint number */
byte_union_alone(bEndpointAddress,
uint8_t dir : 1;
uint8_t : 3;
uint8_t number : 4;
);
/* bmAttributes - Endpoint configuration
* @notes
* - usage usage type (Data, Feedback, Implicit feedback)
* - sync synchronization type (No sync., Async., Adaptive, Sync.)
* - trans transfert type (Control, Isochronous, bulk, Interrupt) */
byte_union_alone(bmAttributes,
uint8_t : 2;
uint8_t usage : 2;
uint8_t sync : 2;
uint8_t trans : 2;
);
/* wPacketSize - Maximum packet size for this endpoint
* @notes
* - size maximum packet size
* - additional additional transaction opportunities per uframe */
word_union_alone(wMaxPacketSize,
uint16_t size :10;
uint16_t additional : 2;
uint16_t : 4;
);
uint8_t bInterval; /* Interval for polling endpoint */
} VPACKED_ALONE;
#include <vhex/usb/descriptor/types.h>
#include <vhex/usb/utils.h>
/* USB_DECLARE_DESC_ENDPOINT - helper to declare endpoint descriptor */
#define USB_DECLARE_DESC_ENDPOINT(name, ...) \
struct usb_descriptor_endpoint name = \
USB_DECLARE_DESC_ENDPOINT_RAW(__VA_ARGS__)
/* USB_DECLARE_DESC_ENDPOINT_RAW - helper to declare endpoint content */
#define USB_DECLARE_DESC_ENDPOINT_RAW(...) \
{ \
.bLengh = sizeof(struct usb_descriptor_endpoint), \
.bDescriptorType = USB_DESCRIPTOR_ENDPOINT, \
__VA_ARGS__ \
}
#endif /* __VHEX_USB_DESCRIPTOR_ENDPOINT_H__ */

View File

@ -0,0 +1,35 @@
#ifndef __VHEX_USB_DESCRIPTOR_INTERFACE_H__
#define __VHEX_USB_DESCRIPTOR_INTERFACE_H__ 1
#include <vhex/defs/types.h>
/* usb_descriptor_interface - USB Interface Descriptor struct */
struct usb_descriptor_interface {
uint8_t bLengh; /* size of this descriptor in bytes */
uint8_t bDescriptorType; /* descriptor type (USB_DESCRIPTOR_DEVICE) */
uint8_t bInterfaceNumber; /* the number of this interface */
uint8_t bAlternateSetting; /* used to select an alternate settings */
uint8_t bNumEndpoints; /* number of endpoint (except endpoint 0) */
uint8_t bInterfaceClass; /* class code */
uint8_t bInterfaceSubClass; /* subclass code */
uint8_t bInterfaceProtocol; /* protocol code */
uint8_t iInterface; /* index of string desc. for this interface */
} VPACKED_ALONE;
#include <vhex/usb/descriptor/types.h>
#include <vhex/usb/utils.h>
/* USB_DECLARE_DESC_INTERFACE - helper to declare interface descriptor */
#define USB_DECLARE_DESC_INTERFACE(name, ...) \
struct usb_descriptor_interface name = \
USB_DECLARE_DESC_INTERFACE_RAW(__VA_ARGS__)
/* USB_DECLARE_DESC_INTERFACE_RAW - helper to declare interface content */
#define USB_DECLARE_DESC_INTERFACE_RAW(...) \
{ \
.bLengh = sizeof(struct usb_descriptor_interface), \
.bDescriptorType = USB_DESCRIPTOR_INTERFACE, \
__VA_ARGS__ \
}
#endif /* __VHEX_USB_DESCRIPTOR_DEVICE_H__ */

View File

@ -0,0 +1,9 @@
#ifndef __VHEX_USB_DESCRIPTOR_TYPES_H__
#define __VHEX_USB_DESCRIPTOR_TYPES_H__ 1
#define USB_DESCRIPTOR_DEVICE 1
#define USB_DESCRIPTOR_CONFIGURATION 2
#define USB_DESCRIPTOR_INTERFACE 4
#define USB_DESCRIPTOR_ENDPOINT 7
#endif /* __VHEX_USB_DESCRIPTOR_TYPES_H__ */

View File

@ -0,0 +1,28 @@
#ifndef __VHEX_USB_DEVICE_H__
#define __VHEX_USB_DEVICE_H__ 1
#include <vhex/defs/types.h>
#include <vhex/usb/descriptor/device.h>
#include <vhex/usb/descriptor/configuration.h>
#include <vhex/usb/descriptor/interface.h>
#include <vhex/usb/descriptor/endpoint.h>
struct usb_full_interface {
struct usb_descriptor_interface *descriptor;
char **strs;
struct usb_descriptor_endpoint **endpoint;
};
struct usb_full_config {
struct usb_descriptor_configuration *descriptor;
char **strs;
struct usb_full_interface **interface;
};
struct usb_full_device {
struct usb_descriptor_device *descriptor;
char **strs;
struct usb_full_config **config;
};
#endif /* __VHEX_USB_DEVICE_H__ */

View File

@ -0,0 +1,20 @@
#ifndef __VHEX_USB_UTILS_H__
#define __VHEX_USB_UTILS_H__ 1
/* USB_WORD_TO() - convert word data to USB compatible one */
#define USB_WORD_TO(data) ((((data) & 0xff00) >> 8) | (((data) & 0x00ff) << 8))
/* USB_REQ_DESCT_* - USB GET_DESCRIPTOR request type list */
enum {
USB_REQ_DESCT_DEVICE = 1,
USB_REQ_DESCT_CONFIG = 2,
USB_REQ_DESCT_STRING = 3,
USB_REQ_DESCT_INTERFACE = 4,
USB_REQ_DESCT_ENDPOINT = 5,
USB_REQ_DESCT_DEVQUAL = 6,
USB_REQ_DESCT_OSC = 7,
USB_REQ_DESCT_POWER = 8,
USB_REQ_DESCT_OTG = 9,
};
#endif /* __VHEX_USB_UTILS_H__ */

View File

@ -0,0 +1,150 @@
#include <vhex/driver/mpu/sh/sh7305/usb.h>
#include <vhex/driver/cpu.h>
#include <vhex/usb.h>
#include <string.h>
//---
// Internals
//---
/* abitrary USB configuration limit (TODO : update me?) */
#define __SH7305_USB_MAX_DC_CONF 2
#define __SH7305_USB_MAX_DC_INTR 4
#define __SH7305_USB_MAX_DC_ENDP 9
/* internal copy of each descriptor (TODO : update me?) */
struct usb_descriptor_device __sh7305_usb_dc_device;
struct usb_descriptor_configuration __sh7305_usb_dc_conf[__SH7305_USB_MAX_DC_CONF];
struct usb_descriptor_interface __sh7305_usb_dc_interf[__SH7305_USB_MAX_DC_INTR];
struct usb_descriptor_endpoint __sh7305_usb_dc_endpoint[__SH7305_USB_MAX_DC_ENDP];
/* sh7305_conf_check_conf() : check and patch interface desc. */
static int sh7305_conf_check_endpoint(
struct usb_descriptor_endpoint **endpoint,
size_t *total
) {
int pipe_id;
int i;
if (endpoint == NULL)
return -3;
for (i = 0 ; endpoint[i] != NULL ; ++i)
{
if (i >= __SH7305_USB_MAX_DC_ENDP) {
usb_logger_write("- too many endpoint (%d)\n", i);
return -4;
}
*total += sizeof(struct usb_descriptor_endpoint);
pipe_id = sh7305_usb_pipe_find(endpoint[i]->bmAttributes.trans);
if (pipe_id < 0)
return pipe_id;
endpoint[i]->bEndpointAddress.number = pipe_id;
memcpy(
&__sh7305_usb_dc_endpoint[i],
endpoint[i],
sizeof(struct usb_descriptor_endpoint)
);
usb_logger_write("- use pipe %d\n", pipe_id);
}
return i;
}
/* sh7305_conf_check_conf() : check and patch interface desc. */
static int sh7305_conf_check_interface(
struct usb_full_interface **interface,
size_t *total
) {
int nbendpoint;
int i;
if (interface == NULL)
return -3;
for (i = 0 ; interface[i] != NULL ; ++i)
{
if (i >= __SH7305_USB_MAX_DC_INTR) {
usb_logger_write("- too many interface (%d)\n", i);
return -4;
}
//FIXME : check strings
*total += sizeof(struct usb_descriptor_interface);
nbendpoint = sh7305_conf_check_endpoint(interface[i]->endpoint, total);
if (nbendpoint < 0)
return nbendpoint;
interface[i]->descriptor->bInterfaceNumber = i + 1;
interface[i]->descriptor->bNumEndpoints = nbendpoint;
memcpy(
&__sh7305_usb_dc_interf[i],
interface[i],
sizeof(struct usb_descriptor_interface)
);
usb_logger_write("- use interface %d\n", i + 1);
}
return i;
}
/* sh7305_conf_check_conf() : check and patch configuration desc. */
static int sh7305_conf_check_conf(struct usb_full_config **config)
{
int nbinterf;
size_t total;
int i;
if (config == NULL)
return -2;
for (i = 0 ; config[i] != NULL ; ++i)
{
if (i >= __SH7305_USB_MAX_DC_CONF) {
usb_logger_write("- too many configuration (%d)\n", i);
return -4;
}
//FIXME : check strings
total = sizeof(struct usb_descriptor_configuration);
nbinterf = sh7305_conf_check_interface(config[i]->interface, &total);
if (nbinterf < 0)
return nbinterf;
config[i]->descriptor->wTotalLengh = total;
config[i]->descriptor->bNumInterfaces = nbinterf;
config[i]->descriptor->bConfigurationValue = i + 1;
memcpy(
&__sh7305_usb_dc_conf[i],
config[i],
sizeof(struct usb_descriptor_configuration)
);
usb_logger_write("- use configuration %d\n", i + 1);
}
return i;
}
//---
// Public API
//---
/* sh7305_usb_configuration_resolve() : check and resolve USB configuration */
int sh7305_usb_configuration_resolve(struct usb_full_device *device)
{
int nbconf;
if (device == NULL)
return -1;
//FIXME : check string validity
cpu_atomic_start();
/* patch configuration descriptors */
nbconf = sh7305_conf_check_conf(device->config);
if (nbconf < 0)
return nbconf;
/* patch device descriptor */
device->descriptor->bNumConfigurations = nbconf;
memcpy(
&__sh7305_usb_dc_device,
device->descriptor,
sizeof(struct usb_descriptor_device)
);
cpu_atomic_end();
return 0;
}

View File

@ -0,0 +1,36 @@
#include <vhex/driver/mpu/sh/sh7305/usb.h>
/* sh7305_usb_dcp_write() : send data through DCP pipe */
int sh7305_usb_dcp_write(void *buffer, size_t n)
{
//FIXME : common interface with other pipe
//FIXME : check buffer size (block send)
//
/* force kevin */
SH7305_USB_INTSTS0_CLEAR(VALID);
/* setup to write mode */
SH7305_USB.CFIFOSEL.ISEL = 1;
SH7305_USB.CFIFOSEL.CURPIPE = 0;
SH7305_USB.CFIFOSEL.BIGEND = 1;
SH7305_USB_REG_SYNC(SH7305_USB.CFIFOSEL.ISEL == 0);
SH7305_USB_REG_SYNC(SH7305_USB.DCPCTR.BSTS == 0);
/* send data */
SH7305_USB.DCPCTR.PID = 1;
for (size_t i = 0; i < n; ++i) {
*((volatile uint8_t*)&SH7305_USB.CFIFO) = ((uint8_t*)buffer)[i];
}
/* commit transfert */
SH7305_USB.CFIFOCTR.BVAL = 1;
SH7305_USB.DCPCTR.CCPL = 1;
usb_logger_write(
"DCPCTR=%04X-CFIFOSEL=%04X-INTSTS=%04X\n"
"buffer = %d\n",
SH7305_USB.DCPCTR.word, SH7305_USB.CFIFOSEL.word, SH7305_USB.INTSTS0.word,
n);
return n;
}

View File

@ -4,10 +4,48 @@
/* sh7305_usb_interrupt_handler() : interrupt handler invoked by hardware */
void sh7305_usb_interrupt_handler(void)
{
dclear(C_WHITE);
dtext(0, 0, C_BLACK, "USB INTERRUPT HANDLER !!!\n");
dupdate();
usb_logger_write("USB INTERRUPT HANDLER !!!!!\n");
while (1) { __asm__ volatile ("nop"); }
{ static char const * const device_st[] = {
"powered", "default", "address", "configured",
"suspended-powered", "suspended-default", "suspended-address",
"suspended-configured",
};
/* Save PIPESEL to avoid concurrent access issues */
uint16_t pipesel = SH7305_USB.PIPESEL.word;
if(SH7305_USB.INTSTS0.VBINT)
{
SH7305_USB_INTSTS0_CLEAR(VBINT);
usb_logger_write("VBUS %s\n", SH7305_USB.INTSTS0.VBSTS ? "up" : "down");
}
else if(SH7305_USB.INTSTS0.CTRT)
{
SH7305_USB_INTSTS0_CLEAR(CTRT);
if(SH7305_USB.INTSTS0.VALID)
sh7305_usb_request_handle();
}
else if(SH7305_USB.INTSTS0.DVST)
{
SH7305_USB_INTSTS0_CLEAR(DVST);
usb_logger_write("DVST %s", device_st[SH7305_USB.INTSTS0.DVSQ]);
if(SH7305_USB.INTSTS0.DVSQ == SH7305_USB_DVSQ_ADDRESS) {
usb_logger_write(": %04x\n", SH7305_USB.USBADDR.word);
} else {
usb_logger_write("\n");
}
//TODO : handle config
}
else {
dclear(C_WHITE);
dprint(
0, 0, C_BLACK,
"USB INTERRUPT HANDLER (%02X) !!!\n",
SH7305_USB.INTSTS0.word
);
dupdate();
while (1) { __asm__ volatile ("nop"); }
}
/* Restore PIPESEL which can have been used for transfers */
SH7305_USB.PIPESEL.word = pipesel;
}

View File

@ -7,10 +7,18 @@
//---
/* sh7305_usb_open() : power on the module and setup USB module */
int sh7305_usb_open(void *_, void *__)
int sh7305_usb_open(struct usb_full_device *device)
{
int ret;
usb_logger_write("-- Open USB ---\n");
/* check and update device configuration */
usb_logger_write("Configuration check...\n");
ret = sh7305_usb_configuration_resolve(device);
if (ret != 0)
return ret;
/* handle hardware power routine */
if (sh7305_usb_hpowered() == false) {
usb_logger_write("Poweron the hardware module...\n");
@ -90,7 +98,7 @@ int sh7305_usb_open(void *_, void *__)
* - VBSE =1 enable VBUS interruption
* - RSME =0 disable Resume interruption
* - SOFE =0 disable Frame Number Update interruption
* - DVSE =0 disable Device State Transition
* - DVSE =0 enable Device State Transition
* - CTRE =0 disable Control Transfert Stage Transition
* - BEMPE =0 disable Buffer Empty interrupt
* - NRDYE =0 disable Buffer Not Ready interrupt
@ -98,8 +106,8 @@ int sh7305_usb_open(void *_, void *__)
SH7305_USB.INTENB0.VBSE = 1;
SH7305_USB.INTENB0.RSME = 0;
SH7305_USB.INTENB0.SOFE = 0;
SH7305_USB.INTENB0.DVSE = 0;
SH7305_USB.INTENB0.CTRE = 0;
SH7305_USB.INTENB0.DVSE = 1;
SH7305_USB.INTENB0.CTRE = 1;
SH7305_USB.INTENB0.BEMPE = 0;
SH7305_USB.INTENB0.NRDYE = 0;
SH7305_USB.INTENB0.BEMPE = 0;
@ -109,6 +117,14 @@ int sh7305_usb_open(void *_, void *__)
SH7305_USB.NRDYENB.word = 0x0000;
SH7305_USB.BEMPENB.word = 0x0000;
/* clear interrupt flags */
SH7305_USB_INTSTS0_CLEAR(VBINT);
SH7305_USB_INTSTS0_CLEAR(RESM);
SH7305_USB_INTSTS0_CLEAR(SOFR);
SH7305_USB_INTSTS0_CLEAR(DVST);
SH7305_USB_INTSTS0_CLEAR(CTRT);
SH7305_USB_INTSTS0_CLEAR(VALID);
/* install hardware interrupt handler and enable USB interruption */
sh7305_intc_install_inth_generic(
0xa20,

View File

@ -0,0 +1,55 @@
#include <vhex/driver/mpu/sh/sh7305/usb.h>
#include <vhex/driver/cpu.h>
//---
// Internals
//---
/* internal pipe bitmap used for pipe status snapshot */
static uint16_t pipe_bitmap = 0x0000;
/* sh7305_pipe_reserve() : try to reserve a pipe */
static int sh7305_pipe_reserve(int pipe)
{
int ret;
cpu_atomic_start();
ret = -1;
if ((pipe_bitmap & (0x0001 << pipe)) == 0x0000) {
pipe_bitmap |= (0x0001 << pipe);
ret = 0;
}
cpu_atomic_end();
return ret;
}
//---
// Public API
//---
/* sh7305_usb_pipe_find() : try to find a pipe */
int sh7305_usb_pipe_find(int type)
{
int min;
int max;
max = -1;
min = -1;
/* Isochronous transfert: use pipe 1,2 */
if (type == 1) min=1, max=2;
/* BULK transfer: use pipe 1..5 */
if (type == 2) min=1, max=5;
/* Interrupt transfer: use pipe 6..9 */
if (type == 3) min=6, max=9;
/* Start from the end to avoir using Isochronous pipe for BULK */
for (int pipe = max ; pipe >= min ; pipe--) {
if (sh7305_pipe_reserve(pipe) == 0)
return pipe;
}
/* no pipe found, return error */
return -1;
}

View File

@ -0,0 +1,190 @@
#include <vhex/driver/mpu/sh/sh7305/usb.h>
#include <vhex/usb/utils.h>
#include <vhex/display.h>
#include <vhex/usb.h>
#include <stdarg.h>
//---
// Internal error API
//---
/* defined in <configuration.c> */
extern struct usb_descriptor_device __sh7305_usb_dc_device;
extern struct usb_descriptor_configuration *__sh7305_usb_dc_conf;
extern struct usb_descriptor_interface *__sh7305_usb_dc_interf;
extern struct usb_descriptor_endpoint *__sh7305_usb_dc_endpoint;
/* sh7305_usb_request_unimplemented() : not implemented request */
static void sh7305_usb_request_unimplemented(
char const * const name,
int wValue,
int wIndex,
int wLength
) {
dclear(C_WHITE);
dprint(0, 0, C_BLACK, "%s (%d, %d, %d)", name, wValue, wIndex, wLength);
dupdate();
while (1) { __asm__ volatile ("sleep"); }
}
/* sh7305_usb_request_error() : USB request error */
static void sh7305_usb_request_error(char const * const text, ...)
{
va_list ap;
va_start(ap, text);
dclear(C_WHITE);
dvprint(0, 0, C_BLACK, text, ap);
dupdate();
while (1) { __asm__ volatile ("sleep"); }
}
/* sh7305_usb_request_get_descriptor() : send descriptor through DCP */
static void sh7305_usb_request_get_descriptor(int wValue, int wIndex, int wLength)
{
int type;
int indx;
(void)wIndex;
(void)wLength;
/* fetch descriptor request */
type = (wValue & 0xff00) >> 8;
indx = (wValue & 0x00ff) >> 0;
/* handle request description type */
if (type == USB_REQ_DESCT_DEVICE) {
usb_logger_write("DCP write DEVICE_DESC\n");
sh7305_usb_dcp_write(
&__sh7305_usb_dc_device,
sizeof(struct usb_descriptor_device)
);
return;
}
if (type == USB_REQ_DESCT_CONFIG) {
sh7305_usb_request_unimplemented("GET_DESC_CONF", indx, 0, 0);
return;
}
if (type == USB_REQ_DESCT_STRING) {
sh7305_usb_request_unimplemented("GET_DESC_STR", indx, 0, 0);
return;
}
if (type == USB_REQ_DESCT_INTERFACE) {
sh7305_usb_request_unimplemented("GET_DESC_INTERFACE", indx, 0, 0);
return;
}
if (type == USB_REQ_DESCT_ENDPOINT) {
sh7305_usb_request_unimplemented("GET_DESC_ENDPOINT", indx, 0, 0);
return;
}
if (type == USB_REQ_DESCT_DEVQUAL) {
sh7305_usb_request_unimplemented("GET_DESC_DEVQUAL", indx, 0, 0);
return;
}
if (type == USB_REQ_DESCT_OSC) {
sh7305_usb_request_unimplemented("GET_DESC_OSC", indx, 0, 0);
return;
}
if (type == USB_REQ_DESCT_POWER) {
sh7305_usb_request_unimplemented("GET_DESC_POWER", indx, 0, 0);
return;
}
if (type == USB_REQ_DESCT_OTG) {
sh7305_usb_request_unimplemented("GET_DESC_OTG", indx, 0, 0);
return;
}
/* handle USB error */
sh7305_usb_request_error(
"GET_DESCRIPTOR : unable to resolve type %d (%04X)",
type, wValue
);
}
//---
// Public API
//---
/* sh7305_usb_request_handle() : handle USB request */
void sh7305_usb_request_handle(void)
{
int bmRequestType;
int bRequest;
int wValue;
int wIndex;
int wLength;
/* fetch request information */
bmRequestType = SH7305_USB.USBREQ.BMREQUEST;
bRequest = SH7305_USB.USBREQ.BREQUEST;
wValue = SH7305_USB.USBVAL.word;
wIndex = SH7305_USB.USBINDX.word;
wLength = SH7305_USB.USBLENG.word;
/* clear VALID bits */
SH7305_USB_INTSTS0_CLEAR(VALID);
/* check GET request */
if (bmRequestType == 0x80) {
if (bRequest == SH7305_USB_REQT_GET_STATUS) {
sh7305_usb_request_unimplemented("GET_STATUS", wValue, wIndex, wLength);
return;
}
if (bRequest == SH7305_USB_REQT_GET_DESCRIPTOR) {
sh7305_usb_request_get_descriptor(wValue, wIndex, wLength);
return;
}
if (bRequest == SH7305_USB_REQT_GET_CONFIGURATION) {
sh7305_usb_request_unimplemented(
"GET_CONFIGURATION", wValue, wIndex, wLength
);
return;
}
usb_logger_write("request: unable to resolve bRequest %d\n", bRequest);
return;
}
/* check SET request */
if (bmRequestType == 0x00) {
if (bRequest == SH7305_USB_REQT_CLEAR_FEATURE) {
sh7305_usb_request_unimplemented(
"CLEAR_FEATURE", wValue, wIndex, wLength
);
return;
}
if (bRequest == SH7305_USB_REQT_SET_FEATURE) {
sh7305_usb_request_unimplemented(
"SET_FEATURE", wValue, wIndex, wLength
);
return;
}
if (bRequest == SH7305_USB_REQT_SET_ADDRESS) {
sh7305_usb_request_unimplemented(
"SET_ADDRESS", wValue, wIndex, wLength
);
return;
}
if (bRequest == SH7305_USB_REQT_SET_DESCRIPTOR) {
sh7305_usb_request_unimplemented(
"SET_DESCRIPTOR", wValue, wIndex, wLength
);
return;
}
if (bRequest == SH7305_USB_REQT_SET_CONFIGURATION) {
sh7305_usb_request_unimplemented(
"SET_CONFIGURATION", wValue, wIndex, wLength
);
return;
}
usb_logger_write("request: unable to resolve bRequest %d\n", bRequest);
return;
}
/* non-standar error */
sh7305_usb_request_error(
"request: unable to resolve bnRequestType %d\n", bmRequestType
);
}

View File

@ -8,17 +8,42 @@
// User-level API
//---
/* dvprint() : display formated text (vargs version) */
did_t dvprint(int x, int y, int fg, char const * const text, va_list ap)
{
char buff[1024];
vsnprintf(buff, 1024, text, ap);
return (dtext_opt(x, y, fg, C_NONE, DTEXT_LEFT | DTEXT_TOP, buff, -1));
}
/* dprint() : display formated string */
did_t dprint(int x, int y, int fg, char const * const text, ...)
{
va_list ap;
char buff[1024];
did_t did;
va_start(ap, text);
vsnprintf(buff, 1024, text, ap);
did = dvprint(x, y, fg, text, ap);
va_end(ap);
return (dtext_opt(x, y, fg, C_NONE, DTEXT_LEFT | DTEXT_TOP, buff, -1));
return did;
}
/* dvprint_opt(): Display a string of text */
did_t dvprint_opt(
int x, int y,
int fg, int bg,
int align,
char const *text,
va_list ap
) {
char buff[1024];
vsnprintf(buff, 1024, text, ap);
return (dtext_opt(x, y, fg, bg, align, buff, -1));
}
/* dprint_opt(): Display a string of text */
@ -29,11 +54,11 @@ did_t dprint_opt(
char const *text, ...
) {
va_list ap;
char buff[1024];
did_t did;
va_start(ap, text);
vsnprintf(buff, 1024, text, ap);
did = dvprint_opt(x, y, fg, bg, align, text, ap);
va_end(ap);
return (dtext_opt(x, y, fg, bg, align, buff, -1));
return did;
}