VxKernel 0.6.0-17 : Add RTC driver + prepare FS support
@add <> include/vhex/display/draw/rect | add filled rectangle API <> src/display/draw/drect | add filled rectangle drawing API <> board/fxcg50/ | add devices special section (WIP) <> include/vhex/device | add device structure (WIP) <> include/vhex/driver/mpu/sh/sh7305/ | [intc] add primitive which allow dummy default interrupt handler | [rtc] add complete RTC hardware structure | [rtc] add hardware-level kernel API <> include/vhex/fs | add file system abstraction API (WIP) | add Fugue FAT file system abstraction API (WIP) <> include/vhex/rtc | add RTC user-level API | add driver-level interface | add kernel-level types <> src/fs | add base Fugue abstraction (WIP) | add libc functions (WIP) @update <> include/vhex/display/draw/text | merge halign and valign argument | add special alignment flags <> include/vhex/driver | add RTC driver flags <> include/vhex/driver/mpu/sh/sh7305/cpg | rename weird field | add Spread Spectrum emulator field | properly expand LSTATS register <> src/driver/mpu/sh/sh7305 | [intc] allow user-level interrupt handler installation | [intc] expose common interrupt handler | [rtc] add RTC entire driver <> src/driver/scree/r61524 | use complete VRAM instead of fragmented render @fix <> src/display | [text] fix height for text display geometry | [text] fix alignment calculation | [dclear] fix geometry support <> src/driver/mpu/sh/sh7305 | [cpg] fix driver installation | [cpg] fix driver spread spectrum | [cpg] fix driver declaration | [tmu] fix exception with the profiling primitives
This commit is contained in:
parent
585254cb2e
commit
e8e63016d5
|
@ -9,7 +9,8 @@ modules = [
|
|||
'hypervisor',
|
||||
'keyboard',
|
||||
'kmalloc',
|
||||
'timer'
|
||||
'timer',
|
||||
'rtc',
|
||||
]
|
||||
|
||||
[drivers]
|
||||
|
|
|
@ -60,6 +60,13 @@ SECTIONS
|
|||
_vhex_modules_end = . ;
|
||||
} > userram
|
||||
|
||||
/* Exposed device interfaces (.vhex.device) */
|
||||
.vhex.device : {
|
||||
_vhex_devices_start = . ;
|
||||
KEEP(*(.vhex.device));
|
||||
_vhex_devices_end = . ;
|
||||
} > userram
|
||||
|
||||
/* Read-only sections */
|
||||
.rodata : {
|
||||
/* Read-Only data */
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
#ifndef __VHEX_DEVICE__
|
||||
# define __VHEX_DEVICE__
|
||||
|
||||
#include <vhex/defs/attributes.h>
|
||||
#include <vhex/defs/types.h>
|
||||
|
||||
struct vhex_device
|
||||
{
|
||||
/* device name */
|
||||
const char * const name;
|
||||
|
||||
/* device flags */
|
||||
byte_union(flags,
|
||||
uint8_t :1;
|
||||
uint8_t :1;
|
||||
uint8_t :1;
|
||||
uint8_t :1;
|
||||
|
||||
uint8_t :1;
|
||||
uint8_t :1;
|
||||
uint8_t :1;
|
||||
uint8_t FS :1;
|
||||
);
|
||||
|
||||
/* device primitives */
|
||||
struct {
|
||||
int (*init)(void);
|
||||
int (*open)(void **data, const char *pathname, int flags, int mode);
|
||||
ssize_t (*write)(void *data, const void *buf, size_t size);
|
||||
ssize_t (*read)(void *data, void *buf, size_t size);
|
||||
off_t (*lseek)(void *data, off_t offset, int whence);
|
||||
int (*close)(void *data);
|
||||
int (*quit)(void);
|
||||
} primitives;
|
||||
};
|
||||
|
||||
/* VHEX_DECLARE_DEVICE(): Declare a device for the kernel
|
||||
|
||||
Use this macro to declare a device by passing it the name of a
|
||||
vhex_device structure. This macro moves the structure to the
|
||||
`.vhex.device` sections, which are automatically traversed at startup. */
|
||||
#define VHEX_DECLARE_DEVICE(name) \
|
||||
VSECTION(".vhex.device") extern struct vhex_device name;
|
||||
|
||||
|
||||
//---
|
||||
// Internal driver control
|
||||
//
|
||||
// The following data is exposed for introspection and debugging purposes; it
|
||||
// is not part of the vhex API. There is *no stability guarantee* that the
|
||||
// following types and functions will remain unchanged in future minor and
|
||||
// patch versions.
|
||||
//---
|
||||
|
||||
/* Number of drivers in the (vhex_drivers) array */
|
||||
#define vhex_device_count() \
|
||||
((struct vhex_device *)&vhex_devices_end \
|
||||
- (struct vhex_device *)&vhex_devices_start)
|
||||
|
||||
/* driver table */
|
||||
#define vhex_device_table() \
|
||||
((struct vhex_device *)&vhex_devices_start)
|
||||
|
||||
/* provided by the linker script */
|
||||
extern uintptr_t vhex_devices_start;
|
||||
extern uintptr_t vhex_devices_end;
|
||||
|
||||
#endif /* __VHEX_DEVICE__ */
|
|
@ -43,7 +43,7 @@ struct vhex_driver
|
|||
|
||||
/* default flags for the driver */
|
||||
byte_union(flags,
|
||||
uint8_t :1;
|
||||
uint8_t RTC :1;
|
||||
uint8_t KEYBOARD :1;
|
||||
uint8_t TIMER :1;
|
||||
uint8_t DISPLAY :1;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
/* sh7305_cpg - Clock Pulse Generator registers
|
||||
Fields marked with [*] don't have the meaning described in the SH7724
|
||||
documentation. */
|
||||
struct sh7305_cpg
|
||||
struct __sh7305_cpg
|
||||
{
|
||||
lword_union(FRQCR,
|
||||
uint32_t KICK :1; /* Flush FRQCRA modifications */
|
||||
|
@ -25,7 +25,7 @@ struct sh7305_cpg
|
|||
uint32_t SFC :4; /* Sphi divider 1 [*] */
|
||||
uint32_t BFC :4; /* Bphi divider 1 [*] */
|
||||
uint32_t :4;
|
||||
uint32_t P1FC :4; /* Pphi divider 1 [*] */
|
||||
uint32_t PFC :4; /* Pphi divider 1 [*] */
|
||||
);
|
||||
pad(0x4);
|
||||
|
||||
|
@ -83,7 +83,8 @@ struct sh7305_cpg
|
|||
|
||||
lword_union(SSCGCR,
|
||||
uint32_t SSEN :1; /* Spread Spectrum Enable */
|
||||
uint32_t :31;
|
||||
uint32_t :30;
|
||||
uint32_t SSEN_EMU:1; /* Emulateur enable */
|
||||
);
|
||||
pad(0x8);
|
||||
|
||||
|
@ -95,11 +96,14 @@ struct sh7305_cpg
|
|||
);
|
||||
pad(0x0c);
|
||||
|
||||
uint32_t LSTATS;
|
||||
lword_union(LSTATS,
|
||||
uint32_t :31;
|
||||
uint32_t FRQF : 1; /* frequency changing status */
|
||||
);
|
||||
|
||||
} VPACKED(4);
|
||||
|
||||
#define SH7305_CPG (*((volatile struct sh7305_cpg *)0xa4150000))
|
||||
#define SH7305_CPG (*((volatile struct __sh7305_cpg *)0xa4150000))
|
||||
|
||||
//---
|
||||
// kernel-level API
|
||||
|
|
|
@ -465,4 +465,7 @@ extern void *sh7305_intc_install_inth(int blockid, void *gate, size_t size);
|
|||
/* sh7305_intc_priority() : set the interrupt name priority */
|
||||
extern int sh7305_intc_priority(int intname, int level);
|
||||
|
||||
/* sh7305_intc_generic_handler() : install generic interrupt handler */
|
||||
extern void *sh7305_intc_generic_handler(int event_code, void *user_inth);
|
||||
|
||||
#endif /* __VHEX_ARCH_SH7305_INTC__ */
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
#ifndef __VHEX_DRIVER_MPU_SH_SH7305_RTC__
|
||||
# define __VHEX_DRIVER_MPU_SH_SH7305_RTC__
|
||||
|
||||
#include <vhex/defs/attributes.h>
|
||||
#include <vhex/defs/types.h>
|
||||
|
||||
//---
|
||||
// Hybrid SH7705-SH7305 Real-Time Clock. Refer to:
|
||||
// "Renesas SH7705 Group Hardware Manual"
|
||||
// Section 15: "Real-Time Clock (RTC)"
|
||||
// "Renesas SH7724 User's Manual: Hardware"
|
||||
// Section 28: "Real-Time Clock (RTC)"
|
||||
//---
|
||||
|
||||
/* rtc_BCD2_t - a 2-digit BCD counter with a 1-byte gap */
|
||||
typedef struct
|
||||
{
|
||||
byte_union(,
|
||||
uint8_t TENS :4;
|
||||
uint8_t ONES :4;
|
||||
);
|
||||
pad(1);
|
||||
|
||||
} VPACKED(2) rtc_BCD2_t;
|
||||
|
||||
/* sh7305_rtc - Date and time access, RTC control */
|
||||
struct __sh7305_rtc_s
|
||||
{
|
||||
uint8_t const R64CNT; /* A 64-Hz counter */
|
||||
pad(1);
|
||||
|
||||
rtc_BCD2_t RSECCNT; /* Second count */
|
||||
rtc_BCD2_t RMINCNT; /* Minute count */
|
||||
rtc_BCD2_t RHRCNT; /* Hour count */
|
||||
|
||||
uint8_t RWKCNT; /* Day of week, must be in [0..6] */
|
||||
pad(1);
|
||||
|
||||
rtc_BCD2_t RDAYCNT; /* Day count */
|
||||
rtc_BCD2_t RMONCNT; /* Month count */
|
||||
|
||||
word_union(RYRCNT, /* Year count */
|
||||
uint THOUSANDS :4;
|
||||
uint HUNDREDS :4;
|
||||
uint TENS :4;
|
||||
uint ONES :4;
|
||||
);
|
||||
pad(12); /* Alarm registers... */
|
||||
|
||||
byte_union(RCR1,
|
||||
uint8_t CF :1; /* Carry flag */
|
||||
uint8_t :2;
|
||||
uint8_t CIE :1; /* Carry interrupt enable */
|
||||
uint8_t AIE :1; /* Alarm interrupt enable */
|
||||
uint8_t :2;
|
||||
uint8_t AF :1; /* Alarm flag */
|
||||
);
|
||||
pad(1);
|
||||
|
||||
byte_union(RCR2,
|
||||
uint8_t PEF :1; /* Periodic interrupt flag */
|
||||
uint8_t PES :3; /* Periodic interrupt interval */
|
||||
uint8_t :1;
|
||||
uint8_t ADJ :1; /* 30-second adjustment */
|
||||
uint8_t RESET :1; /* Reset trigger */
|
||||
uint8_t START :1; /* Start bit */
|
||||
);
|
||||
pad(1);
|
||||
|
||||
byte_union(RCR3,
|
||||
uint8_t BEN :1; /* Periodic interrupt flag */
|
||||
uint8_t :7;
|
||||
);
|
||||
pad(1);
|
||||
} VPACKED(4);
|
||||
|
||||
|
||||
#define SH7305_RTC (*((volatile struct __sh7305_rtc_s *)0xa413fec0))
|
||||
|
||||
//---
|
||||
// RTC periodic interrupt
|
||||
// The real-time clock produces a regular interrupt which may be used as a
|
||||
// timer with a maximum frequency of 256 Hz. It is also useful to check
|
||||
// that the clock settings (see <gint/clock.h>) are properly detected, by
|
||||
// comparing the detected frequencies with the RTC.
|
||||
//---
|
||||
|
||||
/* Possible frequency settings for the RTC's interrupt */
|
||||
enum
|
||||
{
|
||||
RTC_500mHz = 7,
|
||||
RTC_1Hz = 6,
|
||||
RTC_2Hz = 5,
|
||||
RTC_4Hz = 4,
|
||||
RTC_16Hz = 3,
|
||||
RTC_64Hz = 2,
|
||||
RTC_256Hz = 1,
|
||||
RTC_NONE = 0,
|
||||
};
|
||||
|
||||
/* rtc_call: Indirect call with up to 4 register arguments */
|
||||
struct rtc_call {
|
||||
void *function;
|
||||
uint32_t args[4];
|
||||
};
|
||||
|
||||
/* RTC_CALL(): Build an callback from function and arguments */
|
||||
#define RTC_CALL(fct, ...) \
|
||||
(struct rtc_call){ \
|
||||
.function = (void*)fct, \
|
||||
.args = { __VA_ARGS__ } \
|
||||
}
|
||||
|
||||
/* rtc_periodic_enable(): Enable the periodic interrupt
|
||||
|
||||
This function sets up the periodic interrupt to invoke the provided callback
|
||||
regularly. As with timers, the callback must return either TIMER_CONTINUE or
|
||||
TIMER_STOP.
|
||||
|
||||
Note that the timing of the first callback is always uncertain. A 1 Hz timer
|
||||
set up when half of the current second is already elapsed will be called for
|
||||
the first time after only 500 ms, for instance.
|
||||
|
||||
@frequency Periodic interrupt frequency
|
||||
@callback Function to call back at the specified frequency
|
||||
Returns true on success, false if the interrupt is already in use. */
|
||||
extern bool sh7305_rtc_periodic_enable(int frequency, struct rtc_call callback);
|
||||
|
||||
/* rtc_periodic_disable(): Stop the periodic interrupt
|
||||
|
||||
This has the same effect as returning TIMER_STOP from the callback, or
|
||||
setting RTC_NONE as the parameter for rtc_periodic_enable(). */
|
||||
extern void sh7305_rtc_periodic_disable(void);
|
||||
|
||||
#endif /* __VHEX_DRIVER_MPU_SH_SH7305_RTC__ */
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef __VHEX_FS_INFORMATION__
|
||||
# define __VHEX_FS_INFORMATION__
|
||||
|
||||
#include <vhex/defs/attributes.h>
|
||||
#include <vhex/defs/types.h>
|
||||
#include <vhex/device.h>
|
||||
|
||||
/* define the default number of file that can be oppened in the same time */
|
||||
#ifndef VHEX_NB_FILE
|
||||
# define VHEX_NB_FILE 8
|
||||
#endif /* VHEX_NB_FILE */
|
||||
|
||||
/* internal file system information */
|
||||
struct __fs_info {
|
||||
struct vhex_device fs;
|
||||
void *table[VHEX_NB_FILE];
|
||||
};
|
||||
|
||||
extern struct __fs_info fs_info;
|
||||
|
||||
//---
|
||||
// Internal API
|
||||
//---
|
||||
|
||||
/* fs_table_reserve() : reserve file descriptor */
|
||||
extern int fs_table_reserve(void **data);
|
||||
|
||||
/* fs_table_find() : find device-specific data */
|
||||
extern int fs_table_find(void **data, int fd);
|
||||
|
||||
/* fs_table_remove() : remove file descriptor */
|
||||
extern int fs_table_remove(int fd);
|
||||
|
||||
#endif /* __VHEX_FS_INFORMATION__ */
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef __VHEX_FS_FUGUE__
|
||||
# define __VHEX_FS_FUGUE__
|
||||
|
||||
#include <vhex/defs/types.h>
|
||||
|
||||
extern int fugue_open(void **data, const char *pathname, int flags, int mode);
|
||||
extern ssize_t fugue_write(void *data, const void *buf, size_t size);
|
||||
extern ssize_t fugue_read(void *data, void *buf, size_t size);
|
||||
extern off_t fugue_lseek(void *data, off_t offset, int whence);
|
||||
extern int fugue_close(void *data);
|
||||
|
||||
#endif /* __VHEX_FS_FUGUE__ */
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef __VHEX_DRIVER_RTC__
|
||||
# define __VHEX_DRIVER_RTC__
|
||||
|
||||
#include <vhex/rtc/types.h>
|
||||
|
||||
/* rtc_get_time(): Read the current time from the RTC
|
||||
@time Pointer to rtc_time_t structure (needs not be initialized) */
|
||||
extern int rtc_get_time(rtc_time_t *time);
|
||||
|
||||
/* rtc_set_time(): Set current time in the RTC
|
||||
If [time->week_day] is not in the valid range, it is set to 0. Other fields
|
||||
are not checked. R64CNT cannot be set to [time->ticks] is ignored.
|
||||
@time Pointer to new time */
|
||||
extern int rtc_set_time(rtc_time_t const *time);
|
||||
|
||||
#endif /* __VHEX_DRIVER_RTC__ */
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef __VHEX_TIMER_INTERFACE__
|
||||
# define __VHEX_TIMER_INTERFACE__
|
||||
|
||||
#include <vhex/rtc/types.h>
|
||||
|
||||
/* rtc_drv_interface - driver interface */
|
||||
struct rtc_drv_interface
|
||||
{
|
||||
int (*rtc_get_time)(rtc_time_t *time);
|
||||
int (*rtc_set_time)(rtc_time_t const *time);
|
||||
};
|
||||
|
||||
#endif /* __VHEX_TIMER_INTERFACE__ */
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef __VHEX_RTC_TYPES__
|
||||
# define __VHEX_RTC_TYPES__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* rtc_time_t: A point in time, representable in the RTC registers
|
||||
|
||||
WARNING: A copy of this definition is used in fxlibc, make sure to keep it
|
||||
in sync. (We don't install kernel headers before compiling the fxlibc, it's
|
||||
kind of a nightmare for the modest build system.) */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t year; /* Years (exact value, e.g. 2018) */
|
||||
uint8_t week_day; /* Day of week, (0=Sunday, 6=Saturday) */
|
||||
uint8_t month; /* Month (0..11) */
|
||||
uint8_t month_day; /* Day of month (1..31) */
|
||||
uint8_t hours; /* Hour (0..23) */
|
||||
uint8_t minutes; /* Minute (0..59) */
|
||||
uint8_t seconds; /* Second (0..59) */
|
||||
uint8_t ticks; /* 128-Hz sub-second counter (0...127) */
|
||||
|
||||
} rtc_time_t;
|
||||
|
||||
#endif /* __VHEX_RTC_TYPES__ */
|
|
@ -9,12 +9,17 @@
|
|||
/* dclear_draw() : real drawing algorithm */
|
||||
void dclear_render(dsurface_t *surface, uint32_t color)
|
||||
{
|
||||
uint32_t *vram = surface->vram;
|
||||
for (size_t i = 0; i < surface->width * (surface->height/2); ++i)
|
||||
vram[i] = color;
|
||||
#if 0
|
||||
uint32_t *vram;
|
||||
int size = (surface->y1 == 220) ? 792 : 1980;
|
||||
|
||||
vram = surface->vram;
|
||||
for (int i = 0; i < size; ++i)
|
||||
vram[i] = color;
|
||||
#endif
|
||||
}
|
||||
|
||||
//---
|
||||
|
|
|
@ -21,7 +21,7 @@ void cpg_clock_freq(struct cpg_clock_frequency *freq)
|
|||
int divb = CPG.FRQCR.BFC;
|
||||
int divi = CPG.FRQCR.IFC;
|
||||
int divs = CPG.FRQCR.SFC;
|
||||
int divp = CPG.FRQCR.P1FC;
|
||||
int divp = CPG.FRQCR.PFC;
|
||||
|
||||
freq->Bphi_div = 1 << (divb + 1);
|
||||
freq->Iphi_div = 1 << (divi + 1);
|
||||
|
@ -47,25 +47,143 @@ void cpg_clock_freq(struct cpg_clock_frequency *freq)
|
|||
//---
|
||||
|
||||
struct cpg_ctx {
|
||||
uint32_t SSCGCR;
|
||||
struct __sh7305_cpg hw;
|
||||
};
|
||||
|
||||
/* __cpg_configure() : configure the CPG */
|
||||
static void __cpg_configure(struct cpg_ctx *state)
|
||||
{
|
||||
(void)state;
|
||||
/* Configure the all bus divier and multiplicator
|
||||
<> PLL : 232.31Mhz (x16)
|
||||
<> Iphi (CPU) : 116.15Mhz (/2)
|
||||
<> Sphi (SuperH) : 58.07Mhz (/4)
|
||||
<> Bphi (BSC) : 58.07Mhz (/4)
|
||||
<> Pphi (peripheral) : 29.03Mhz (/8)
|
||||
*/
|
||||
state->hw.FRQCR.STC = 15;
|
||||
state->hw.FRQCR.IFC = 0;
|
||||
state->hw.FRQCR.SFC = 1;
|
||||
state->hw.FRQCR.BFC = 1;
|
||||
state->hw.FRQCR.PFC = 2;
|
||||
|
||||
/* Configure FSI clock (disable by default) */
|
||||
state->hw.FSICLKCR.CLKSTP = 1;
|
||||
|
||||
/* Configure DD clock (disable by default) */
|
||||
state->hw.DDCLKCR.CLKSTP = 1;
|
||||
|
||||
/* Configure USB clock (disable by default) */
|
||||
state->hw.USBCLKCR.CLKSTP = 1;
|
||||
|
||||
/* Configure PLL and FLL multiplier
|
||||
<> enable PLL
|
||||
<> enable FLL
|
||||
<> disable CKO output stop
|
||||
*/
|
||||
state->hw.PLLCR.PLLE = 1;
|
||||
state->hw.PLLCR.FLLE = 1;
|
||||
state->hw.PLLCR.CKOFF = 0;
|
||||
|
||||
/* Configure PLL multiplication ratio (disable by default) */
|
||||
state->hw.PLL2CR.MUL = 0;
|
||||
|
||||
/* Configure SPU (disable by default) */
|
||||
state->hw.SPUCLKCR.CLKSTP = 1;
|
||||
|
||||
/* Configure Spread Spectrum (force disable) */
|
||||
state->hw.SSCGCR.SSEN_EMU = 0;
|
||||
state->hw.SSCGCR.SSEN = 0;
|
||||
|
||||
/* Configure FLL division/multiplicator
|
||||
<> force FLL multiplication Ratio with x(1/2)
|
||||
<> use 1017 (default value of the module) as multiplicator wich will
|
||||
give us ~16Mhz (Casio use 900 instead of 1017 wich is ~14Mhz):
|
||||
|
||||
( 32768 * 1017 ) / 2 = 16 662 528 Hz
|
||||
( 32768 * 900 ) / 2 = 14 745 600 Hz
|
||||
*/
|
||||
state->hw.FLLFRQ.SELXM = 1;
|
||||
state->hw.FLLFRQ.FLF = 1017;
|
||||
}
|
||||
|
||||
/* __cpg_hsave() : save hardware information */
|
||||
static void __cpg_hsave(struct cpg_ctx *state)
|
||||
{
|
||||
(void)state;
|
||||
state->hw.FRQCR.STC = SH7305_CPG.FRQCR.STC;
|
||||
state->hw.FRQCR.IFC = SH7305_CPG.FRQCR.IFC;
|
||||
state->hw.FRQCR.SFC = SH7305_CPG.FRQCR.SFC;
|
||||
state->hw.FRQCR.BFC = SH7305_CPG.FRQCR.BFC;
|
||||
state->hw.FRQCR.PFC = SH7305_CPG.FRQCR.PFC;
|
||||
|
||||
state->hw.FSICLKCR.DIVB = SH7305_CPG.FSICLKCR.DIVB;
|
||||
state->hw.FSICLKCR.CLKSTP = SH7305_CPG.FSICLKCR.CLKSTP;
|
||||
state->hw.FSICLKCR.SRC = SH7305_CPG.FSICLKCR.SRC;
|
||||
state->hw.FSICLKCR.DIVA = SH7305_CPG.FSICLKCR.DIVA;
|
||||
|
||||
state->hw.DDCLKCR.CLKSTP = SH7305_CPG.DDCLKCR.CLKSTP;
|
||||
state->hw.DDCLKCR.SRC = SH7305_CPG.DDCLKCR.SRC;
|
||||
state->hw.DDCLKCR.DIV = SH7305_CPG.DDCLKCR.DIV;
|
||||
|
||||
state->hw.USBCLKCR.CLKSTP = SH7305_CPG.USBCLKCR.CLKSTP;
|
||||
|
||||
state->hw.PLLCR.PLLE = SH7305_CPG.PLLCR.PLLE;
|
||||
state->hw.PLLCR.FLLE = SH7305_CPG.PLLCR.FLLE;
|
||||
state->hw.PLLCR.CKOFF = SH7305_CPG.PLLCR.CKOFF;
|
||||
|
||||
state->hw.PLL2CR.MUL = SH7305_CPG.PLL2CR.MUL;
|
||||
|
||||
state->hw.SPUCLKCR.CLKSTP = SH7305_CPG.SPUCLKCR.CLKSTP;
|
||||
state->hw.SPUCLKCR.SRC = SH7305_CPG.SPUCLKCR.SRC;
|
||||
state->hw.SPUCLKCR.DIV = SH7305_CPG.SPUCLKCR.DIV;
|
||||
|
||||
state->hw.SSCGCR.SSEN = SH7305_CPG.SSCGCR.SSEN;
|
||||
state->hw.SSCGCR.SSEN_EMU = SH7305_CPG.SSCGCR.SSEN_EMU;
|
||||
|
||||
state->hw.FLLFRQ.SELXM = SH7305_CPG.FLLFRQ.SELXM;
|
||||
state->hw.FLLFRQ.FLF = SH7305_CPG.FLLFRQ.FLF;
|
||||
}
|
||||
|
||||
/* __cpg_hrestore() : restore hardware information */
|
||||
static void __cpg_hrestore(struct cpg_ctx *state)
|
||||
{
|
||||
(void)state;
|
||||
SH7305_CPG.FRQCR.STC = state->hw.FRQCR.STC;
|
||||
SH7305_CPG.FRQCR.IFC = state->hw.FRQCR.IFC;
|
||||
SH7305_CPG.FRQCR.SFC = state->hw.FRQCR.SFC;
|
||||
SH7305_CPG.FRQCR.BFC = state->hw.FRQCR.BFC;
|
||||
SH7305_CPG.FRQCR.PFC = state->hw.FRQCR.PFC;
|
||||
|
||||
SH7305_CPG.FSICLKCR.DIVB = state->hw.FSICLKCR.DIVB;
|
||||
SH7305_CPG.FSICLKCR.CLKSTP = state->hw.FSICLKCR.CLKSTP;
|
||||
SH7305_CPG.FSICLKCR.SRC = state->hw.FSICLKCR.SRC;
|
||||
SH7305_CPG.FSICLKCR.DIVA = state->hw.FSICLKCR.DIVA;
|
||||
|
||||
SH7305_CPG.DDCLKCR.CLKSTP = state->hw.DDCLKCR.CLKSTP;
|
||||
SH7305_CPG.DDCLKCR.SRC = state->hw.DDCLKCR.SRC;
|
||||
SH7305_CPG.DDCLKCR.DIV = state->hw.DDCLKCR.DIV;
|
||||
|
||||
SH7305_CPG.USBCLKCR.CLKSTP = state->hw.USBCLKCR.CLKSTP;
|
||||
|
||||
SH7305_CPG.PLLCR.PLLE = state->hw.PLLCR.PLLE;
|
||||
SH7305_CPG.PLLCR.FLLE = state->hw.PLLCR.FLLE;
|
||||
SH7305_CPG.PLLCR.CKOFF = state->hw.PLLCR.CKOFF;
|
||||
|
||||
SH7305_CPG.PLL2CR.MUL = state->hw.PLL2CR.MUL;
|
||||
|
||||
SH7305_CPG.SPUCLKCR.CLKSTP = state->hw.SPUCLKCR.CLKSTP;
|
||||
SH7305_CPG.SPUCLKCR.SRC = state->hw.SPUCLKCR.SRC;
|
||||
SH7305_CPG.SPUCLKCR.DIV = state->hw.SPUCLKCR.DIV;
|
||||
|
||||
SH7305_CPG.SSCGCR.SSEN = state->hw.SSCGCR.SSEN;
|
||||
SH7305_CPG.SSCGCR.SSEN_EMU = state->hw.SSCGCR.SSEN_EMU;
|
||||
|
||||
SH7305_CPG.FLLFRQ.SELXM = state->hw.FLLFRQ.SELXM;
|
||||
SH7305_CPG.FLLFRQ.FLF = state->hw.FLLFRQ.FLF;
|
||||
|
||||
SH7305_CPG.FRQCR.KICK = 1;
|
||||
while (SH7305_CPG.LSTATS.FRQF != 0) { __asm__ volatile ("nop"); }
|
||||
|
||||
SH7305_CPG.PLL2CR.KICK = 1;
|
||||
while (SH7305_CPG.LSTATS.FRQF != 0) { __asm__ volatile ("nop"); }
|
||||
}
|
||||
|
||||
struct vhex_driver drv_cpg = {
|
||||
|
@ -75,4 +193,4 @@ struct vhex_driver drv_cpg = {
|
|||
.configure = (void*)&__cpg_configure,
|
||||
.state_size = sizeof(struct cpg_ctx)
|
||||
};
|
||||
VHEX_DECLARE_DRIVER(03, drv_cpu);
|
||||
VHEX_DECLARE_DRIVER(03, drv_cpg);
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
#include <vhex/driver/mpu/sh/sh7305/intc.h>
|
||||
#include <vhex/defs/types.h>
|
||||
#include <string.h>
|
||||
|
||||
|
|
@ -120,6 +120,24 @@ void *sh7305_intc_install_inth(int event_code, void *gate, size_t size)
|
|||
);
|
||||
}
|
||||
|
||||
/* sh7305_intc_generic_handler() : install generic interrupt handler */
|
||||
void *sh7305_intc_generic_handler(int event_code, void *user_inth)
|
||||
{
|
||||
extern void vhex_sh7305_intc_generic_handler(void);
|
||||
|
||||
void *h = sh7305_intc_install_inth(
|
||||
event_code,
|
||||
sh7305_intc_generic_handler,
|
||||
32
|
||||
);
|
||||
if(!h) return false;
|
||||
|
||||
*(void **)(h + 28) = user_inth;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
//---
|
||||
// hardware configuration call
|
||||
//---
|
||||
|
|
|
@ -66,3 +66,21 @@ _vhex_inth_sh7305:
|
|||
.first_entry:
|
||||
|
||||
|
||||
/* _vhex_sh7305_intc_generic_handler: Standard interrupt handler
|
||||
|
||||
This is a generic interrupt handler that calls back into a C function,
|
||||
useful for complex handling or simple drivers that benefit more from
|
||||
simplicity than razor-sharp performance. */
|
||||
|
||||
.section .vhex.blocks, "ax"
|
||||
.align 4
|
||||
|
||||
.global _vhex_sh7305_intc_generic_handler /* 32 bytes */
|
||||
|
||||
_vhex_sh7305_intc_generic_handler:
|
||||
mov.l 1f, r1
|
||||
jmp @r1
|
||||
mov r0, r4
|
||||
|
||||
.zero 22 /* Indirect call to be made */
|
||||
1: .long 0 /* Address of the runtime */
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
/* define the private KeyScan context structure */
|
||||
struct keysc_ctx {
|
||||
struct __sh7305_keysc_s keysc;
|
||||
uint16_t iprf;
|
||||
};
|
||||
|
||||
/* hardware configuration call */
|
||||
|
|
|
@ -0,0 +1,231 @@
|
|||
#include <vhex/driver/mpu/sh/sh7305/rtc.h>
|
||||
#include <vhex/driver/mpu/sh/sh7305/intc.h>
|
||||
#include <vhex/rtc/interface.h>
|
||||
#include <vhex/driver.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
//---
|
||||
// RTC periodic interrupt
|
||||
//---
|
||||
|
||||
static struct rtc_call rtc_call;
|
||||
|
||||
/* rtc_periodic interrupt() : internal interrupt handler */
|
||||
static void sh7305_rtc_periodic_inth(void)
|
||||
{
|
||||
int (*routine)(
|
||||
uintptr_t,
|
||||
uintptr_t,
|
||||
uintptr_t,
|
||||
uintptr_t
|
||||
) = rtc_call.function;
|
||||
|
||||
int rc = routine(
|
||||
rtc_call.args[0],
|
||||
rtc_call.args[1],
|
||||
rtc_call.args[2],
|
||||
rtc_call.args[3]
|
||||
);
|
||||
|
||||
/* Clear the interrupt flag */
|
||||
do SH7305_RTC.RCR2.PEF = 0;
|
||||
while(SH7305_RTC.RCR2.PEF);
|
||||
|
||||
/* Stop the interrupt if the callback returns non-zero */
|
||||
if(rc) sh7305_rtc_periodic_disable();
|
||||
}
|
||||
|
||||
/* rtc_periodic_enable(): Enable the periodic interrupt */
|
||||
bool sh7305_rtc_periodic_enable(int frequency, struct rtc_call callback)
|
||||
{
|
||||
/* Refuse to override an existing interrupt */
|
||||
if(SH7305_RTC.RCR2.PES != RTC_NONE) return false;
|
||||
if(frequency == RTC_NONE)
|
||||
{
|
||||
sh7305_rtc_periodic_disable();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Temporarily disable the interrupt and set up the callback */
|
||||
SH7305_RTC.RCR2.PES = RTC_NONE;
|
||||
memcpy(&rtc_call, &callback, sizeof(struct rtc_call));
|
||||
|
||||
/* Clear the interrupt flag */
|
||||
do SH7305_RTC.RCR2.PEF = 0;
|
||||
while(SH7305_RTC.RCR2.PEF);
|
||||
|
||||
/* Enable the interrupt */
|
||||
SH7305_RTC.RCR2.PES = frequency;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* rtc_periodic_disable(): Stop the periodic interrupt */
|
||||
void sh7305_rtc_periodic_disable(void)
|
||||
{
|
||||
SH7305_RTC.RCR2.PES = RTC_NONE;
|
||||
}
|
||||
|
||||
//---
|
||||
// Define driver information
|
||||
//---
|
||||
|
||||
struct rtc_ctx {
|
||||
struct __sh7305_rtc_s rtc;
|
||||
};
|
||||
|
||||
/* __rtc_configure() : configure the RTC */
|
||||
static void __rtc_configure(struct rtc_ctx *state)
|
||||
{
|
||||
/* Clear and disable the carry and alamr interrupts */
|
||||
state->rtc.RCR1.CF = 0;
|
||||
state->rtc.RCR1.CIE = 0;
|
||||
state->rtc.RCR1.AIE = 0;
|
||||
state->rtc.RCR1.AF = 0;
|
||||
|
||||
/* Disable the periodic interrupt flag */
|
||||
state->rtc.RCR2.PEF = 0;
|
||||
state->rtc.RCR2.PES = RTC_NONE;
|
||||
state->rtc.RCR2.ADJ = 0;
|
||||
state->rtc.RCR2.RESET = 1;
|
||||
state->rtc.RCR2.START = 1;
|
||||
|
||||
/* Disable year alarm check */
|
||||
state->rtc.RCR3.BEN = 0;
|
||||
|
||||
/* set the interrupt level (max) */
|
||||
sh7305_intc_priority(INTC_RTC_ATI, 0);
|
||||
sh7305_intc_priority(INTC_RTC_CUI, 0);
|
||||
sh7305_intc_priority(INTC_RTC_PRI, 1);
|
||||
|
||||
/* intall the RTC interupt handler */
|
||||
sh7305_intc_generic_handler(0xaa0, &sh7305_rtc_periodic_inth);
|
||||
}
|
||||
|
||||
/* __rtc_hsave() : save hardware information */
|
||||
static void __rtc_hsave(struct rtc_ctx *state)
|
||||
{
|
||||
/* stop as soon as possible RTC counters */
|
||||
state->rtc.RCR2.START = SH7305_RTC.RCR2.START;
|
||||
SH7305_RTC.RCR2.START = 0;
|
||||
|
||||
state->rtc.RCR1.CF = SH7305_RTC.RCR1.CF;
|
||||
state->rtc.RCR1.CIE = SH7305_RTC.RCR1.CIE;
|
||||
state->rtc.RCR1.AIE = SH7305_RTC.RCR1.AIE;
|
||||
state->rtc.RCR1.AF = SH7305_RTC.RCR1.AF;
|
||||
|
||||
state->rtc.RCR2.PEF = SH7305_RTC.RCR2.PEF;
|
||||
state->rtc.RCR2.PES = SH7305_RTC.RCR2.PES;
|
||||
state->rtc.RCR2.ADJ = SH7305_RTC.RCR2.ADJ;
|
||||
|
||||
state->rtc.RCR3.BEN = SH7305_RTC.RCR3.BEN;
|
||||
}
|
||||
|
||||
/* __rtc_hrestore() : restore hardware information */
|
||||
static void __rtc_hrestore(struct rtc_ctx *state)
|
||||
{
|
||||
/* stop as soon as possible RTC counters */
|
||||
SH7305_RTC.RCR2.START = 0;
|
||||
|
||||
SH7305_RTC.RCR1.CF = state->rtc.RCR1.CF;
|
||||
SH7305_RTC.RCR1.CIE = state->rtc.RCR1.CIE;
|
||||
SH7305_RTC.RCR1.AIE = state->rtc.RCR1.AIE;
|
||||
SH7305_RTC.RCR1.AF = state->rtc.RCR1.AF;
|
||||
|
||||
SH7305_RTC.RCR2.PEF = state->rtc.RCR2.PEF;
|
||||
SH7305_RTC.RCR2.PES = state->rtc.RCR2.PES;
|
||||
SH7305_RTC.RCR2.ADJ = state->rtc.RCR2.ADJ;
|
||||
|
||||
SH7305_RTC.RCR3.BEN = state->rtc.RCR3.BEN;
|
||||
|
||||
SH7305_RTC.RCR2.START = state->rtc.RCR2.START;
|
||||
}
|
||||
|
||||
//---
|
||||
// User API
|
||||
//---
|
||||
|
||||
/* int8(), int16(): Convert BCD to integer */
|
||||
static int int8(uint8_t bcd)
|
||||
{
|
||||
return (bcd & 0x0f) + 10 * (bcd >> 4);
|
||||
}
|
||||
static int int16(uint16_t bcd)
|
||||
{
|
||||
return (bcd & 0xf) + 10 * ((bcd >> 4) & 0xf) + 100 * ((bcd >> 8) & 0xf)
|
||||
+ 1000 * (bcd >> 12);
|
||||
}
|
||||
|
||||
/* bcd8(), bcd16(): Convert integer to BCD */
|
||||
static uint8_t bcd8(int integer)
|
||||
{
|
||||
integer %= 100;
|
||||
return ((integer / 10) << 4) | (integer % 10);
|
||||
}
|
||||
static uint16_t bcd16(int integer)
|
||||
{
|
||||
integer %= 10000;
|
||||
return (bcd8(integer / 100) << 8) | bcd8(integer % 100);
|
||||
}
|
||||
|
||||
/* sh7305_rtc_get_time(): Read the current time from the RTC */
|
||||
int sh7305_rtc_get_time(rtc_time_t *time)
|
||||
{
|
||||
do {
|
||||
SH7305_RTC.RCR1.CF = 0;
|
||||
|
||||
time->ticks = SH7305_RTC.R64CNT;
|
||||
time->seconds = int8(SH7305_RTC.RSECCNT.byte);
|
||||
time->minutes = int8(SH7305_RTC.RMINCNT.byte);
|
||||
time->hours = int8(SH7305_RTC.RHRCNT.byte);
|
||||
time->month_day = int8(SH7305_RTC.RDAYCNT.byte);
|
||||
time->month = int8(SH7305_RTC.RMONCNT.byte);
|
||||
time->year = int16(SH7305_RTC.RYRCNT.word);
|
||||
time->week_day = SH7305_RTC.RWKCNT;
|
||||
|
||||
} while(SH7305_RTC.RCR1.CF != 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* sh7305_rtc_set_time(): Set current time in the RTC */
|
||||
int sh7305_rtc_set_time(rtc_time_t const *time)
|
||||
{
|
||||
int wday = time->week_day;
|
||||
if(wday >= 7) wday = 0;
|
||||
|
||||
do {
|
||||
SH7305_RTC.RCR1.CF = 0;
|
||||
|
||||
SH7305_RTC.RSECCNT.byte = bcd8(time->seconds);
|
||||
SH7305_RTC.RMINCNT.byte = bcd8(time->minutes);
|
||||
SH7305_RTC.RHRCNT.byte = bcd8(time->hours);
|
||||
SH7305_RTC.RDAYCNT.byte = bcd8(time->month_day);
|
||||
SH7305_RTC.RMONCNT.byte = bcd8(time->month);
|
||||
SH7305_RTC.RYRCNT.word = bcd16(time->year);
|
||||
SH7305_RTC.RWKCNT = wday;
|
||||
|
||||
} while(SH7305_RTC.RCR1.CF != 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//---
|
||||
// Declare driver
|
||||
//---
|
||||
|
||||
struct vhex_driver drv_rtc = {
|
||||
.name = "RTC",
|
||||
.hsave = (void*)&__rtc_hsave,
|
||||
.hrestore = (void*)&__rtc_hrestore,
|
||||
.configure = (void*)&__rtc_configure,
|
||||
.state_size = sizeof(struct rtc_ctx),
|
||||
.flags = {
|
||||
.RTC = 1,
|
||||
.SHARED = 0,
|
||||
.UNUSED = 0,
|
||||
},
|
||||
.module_data = &(struct rtc_drv_interface){
|
||||
.rtc_get_time = &sh7305_rtc_get_time,
|
||||
.rtc_set_time = &sh7305_rtc_set_time,
|
||||
}
|
||||
};
|
||||
VHEX_DECLARE_DRIVER(06, drv_rtc);
|
|
@ -381,27 +381,29 @@ int sh7305_tmu_prof_init(timer_prof_t *prof)
|
|||
/* sh7305_tmu_prof_enter(): Start counting time for a function */
|
||||
void sh7305_tmu_prof_enter(timer_prof_t *prof)
|
||||
{
|
||||
prof->elapsed += *tmu_prof_tcnt;
|
||||
if (tmu_prof_tcnt != NULL)
|
||||
prof->elapsed += *tmu_prof_tcnt;
|
||||
}
|
||||
|
||||
/* sh7305_tmu_prof_enter_rec(): Start counting time for a recursive function */
|
||||
void sh7305_tmu_prof_enter_rec(timer_prof_t *prof)
|
||||
{
|
||||
if (!prof->rec++)
|
||||
if (!prof->rec++ && tmu_prof_tcnt != NULL)
|
||||
prof->elapsed += *tmu_prof_tcnt;
|
||||
}
|
||||
|
||||
/* sh7305_tmu_prof_leave_rec(): Start counting time for a recursive function */
|
||||
void sh7305_tmu_prof_leave_rec(timer_prof_t *prof)
|
||||
{
|
||||
if (!--prof->rec)
|
||||
if (!--prof->rec && tmu_prof_tcnt != NULL)
|
||||
prof->elapsed -= *tmu_prof_tcnt;
|
||||
}
|
||||
|
||||
/* sh7305_tmu_prof_leave(): Stop counting time for a function */
|
||||
void sh7305_tmu_prof_leave(timer_prof_t *prof)
|
||||
{
|
||||
prof->elapsed -= *tmu_prof_tcnt;
|
||||
if (tmu_prof_tcnt != NULL)
|
||||
prof->elapsed -= *tmu_prof_tcnt;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
// R61524 driver API
|
||||
//---
|
||||
|
||||
uint32_t vhex_vram[396*(224/2)];
|
||||
|
||||
/* r61524_frame_start() - prepar the screen and reset surfaces */
|
||||
VALIGNED(4) int r61524_frame_start(dsurface_t *surface)
|
||||
{
|
||||
|
@ -30,18 +32,24 @@ VALIGNED(4) int r61524_frame_start(dsurface_t *surface)
|
|||
r61524_select(write_data);
|
||||
|
||||
/* initialize surface information */
|
||||
surface->vram = (void*)0xe5017000;
|
||||
// surface->vram = (void*)0xe5017000;
|
||||
// surface->width = 396;
|
||||
// surface->height = 10;
|
||||
surface->vram = (void*)vhex_vram;
|
||||
surface->width = 396;
|
||||
surface->height = 10;
|
||||
surface->height = 224;
|
||||
surface->x1 = 0;
|
||||
surface->y1 = 0;
|
||||
surface->x2 = 395;
|
||||
surface->y2 = 9;
|
||||
surface->y2 = 223;
|
||||
return (0);
|
||||
}
|
||||
|
||||
VALIGNED(4) int r61524_frame_frag_next(dsurface_t *surface)
|
||||
{
|
||||
(void)surface;
|
||||
return -1;
|
||||
#if 0
|
||||
surface->y1 += 10;
|
||||
if (surface->y1 >= 224) {
|
||||
surface->y1 -= 10;
|
||||
|
@ -52,10 +60,16 @@ VALIGNED(4) int r61524_frame_frag_next(dsurface_t *surface)
|
|||
surface->height = 4;
|
||||
surface->y2 += surface->height;
|
||||
return (0);
|
||||
#endif
|
||||
}
|
||||
|
||||
VALIGNED(4) VWEAK int r61524_frame_frag_send(dsurface_t *surface)
|
||||
{
|
||||
uint16_t *vram = surface->vram;
|
||||
for (int i = 0; i < 396*224; ++i) {
|
||||
r61524_write(vram[i]);
|
||||
}
|
||||
#if 0
|
||||
uint16_t * restrict yram = surface->vram;
|
||||
int size = (surface->y1 == 220) ? 1584 : 3960;
|
||||
|
||||
|
@ -63,6 +77,7 @@ VALIGNED(4) VWEAK int r61524_frame_frag_send(dsurface_t *surface)
|
|||
r61524_write(yram[i]);
|
||||
}
|
||||
return (0);
|
||||
#endif
|
||||
}
|
||||
|
||||
VALIGNED(4) int r61524_frame_end(dsurface_t *surface)
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
#if 0
|
||||
#include <vhex/fs.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
/* fs_table_reserve() : reserve file descriptor */
|
||||
int fs_table_reserve(void **data)
|
||||
{
|
||||
*data = NULL;
|
||||
for (int i = 3 ; i < VHEX_NB_FILE; ++i) {
|
||||
if (fs_info.table[i] == NULL) {
|
||||
fs_info.table[i] = (void*)0xdeadbeef;
|
||||
*data = &fs_info.table[i];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return ENFILE;
|
||||
}
|
||||
|
||||
/* fs_table_find() : find device-specific data */
|
||||
int fs_table_find(void **data, int fd)
|
||||
{
|
||||
*data = NULL;
|
||||
if (fd < 0 || fd >= VHEX_NB_FILE)
|
||||
return EBADF;
|
||||
if (fs_info.table[fd] == NULL)
|
||||
return EBADF;
|
||||
*data = fs_info.table[fd];
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fs_table_remove() : remove file descriptor */
|
||||
int fs_table_remove(int fd)
|
||||
{
|
||||
if (fd < 0 || fd >= VHEX_NB_FILE)
|
||||
return EBADF;
|
||||
if (fs_info.table[fd] == NULL)
|
||||
return EBADF;
|
||||
fs_info.table[fd] = NULL;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,32 @@
|
|||
#include <vhex/fs.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
int close(int fd)
|
||||
{
|
||||
(void)fd;
|
||||
#if 0
|
||||
void *data;
|
||||
|
||||
errno = fs_table_find(&data, fd);
|
||||
if (errno != 0)
|
||||
return -1;
|
||||
|
||||
if (fd >= 0 && fd <= 2) {
|
||||
//TODO:support keyboard
|
||||
//TODO:support display
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fs_info.fs.primitives.write == NULL) {
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
errno = fs_info.fs.primitives.close(data);
|
||||
if (errno != 0)
|
||||
return -1;
|
||||
|
||||
return fs_table_remove(fd);
|
||||
#endif
|
||||
}
|
58
src/fs/fs.c
58
src/fs/fs.c
|
@ -1,28 +1,46 @@
|
|||
#include <unistd.h>
|
||||
#include <vhex/defs/types.h>
|
||||
#if 0
|
||||
#include <vhex/fs.h>
|
||||
#include <vhex/module.h>
|
||||
#include <vhex/device.h>
|
||||
|
||||
ssize_t write(int fd, const void *buf, size_t size)
|
||||
#include <string.h>
|
||||
|
||||
/* module init */
|
||||
|
||||
/* internal file system information */
|
||||
struct __fs_info fs_info;
|
||||
|
||||
/* __fs_init() : initialize the fs module */
|
||||
static void __fs_init(void)
|
||||
{
|
||||
(void)fd;
|
||||
(void)buf;
|
||||
(void)size;
|
||||
struct vhex_device *device = vhex_device_table();
|
||||
for (int i = 0; i < vhex_device_count(); ++i) {
|
||||
if (device[i].flags.FS) {
|
||||
memcpy(
|
||||
&fs_info.fs,
|
||||
&device[i],
|
||||
sizeof(struct vhex_device)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//TODO: initialise STDIN_FILENO
|
||||
//TODO: initialise STDOUT_FILENO
|
||||
//TODO: initialise STDERR_FILENO
|
||||
}
|
||||
|
||||
ssize_t read(int fd, void *buf, size_t size)
|
||||
/* __display_quit() : uninit the fs module */
|
||||
static void __fs_quit(void)
|
||||
{
|
||||
(void)fd;
|
||||
(void)buf;
|
||||
(void)size;
|
||||
//Nothing to do
|
||||
}
|
||||
|
||||
off_t lseek(int fd, off_t offset, int whence)
|
||||
{
|
||||
(void)fd;
|
||||
(void)offset;
|
||||
(void)whence;
|
||||
}
|
||||
/* declare the fs module */
|
||||
|
||||
int close(int fd)
|
||||
{
|
||||
(void)fd;
|
||||
}
|
||||
struct vhex_module mod_fs = {
|
||||
.name = "fs",
|
||||
.init = &__fs_init,
|
||||
.quit = &__fs_quit,
|
||||
};
|
||||
VHEX_DECLARE_MODULE(03, mod_fs);
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
#include <vhex/fs/fugue.h>
|
||||
|
||||
int fugue_close(void *data)
|
||||
{
|
||||
(void)data;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
#if 0
|
||||
#include <vhex/device.h>
|
||||
#include <vhex/fs/fugue.h>
|
||||
|
||||
/* declare device */
|
||||
|
||||
struct vhex_device dev_fugue = {
|
||||
.name = "Fugue",
|
||||
.flags = {
|
||||
.FS = 1
|
||||
},
|
||||
.primitives = {
|
||||
.init = NULL,
|
||||
.open = &fugue_open,
|
||||
.write = &fugue_write,
|
||||
.read = &fugue_read,
|
||||
.lseek = &fugue_lseek,
|
||||
.close = &fugue_close,
|
||||
.quit = NULL
|
||||
}
|
||||
};
|
||||
VHEX_DECLARE_DEVICE(dev_fugue);
|
||||
#endif
|
|
@ -0,0 +1,8 @@
|
|||
#include <vhex/fs/fugue.h>
|
||||
|
||||
off_t fugue_lseek(void *data, off_t offset, int whence)
|
||||
{
|
||||
(void)data;
|
||||
(void)offset;
|
||||
(void)whence;
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
#if 0
|
||||
#include <vhex/fs/fugue.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
/* fugue_open() : try to open file */
|
||||
int fugue_open(void **data, const char *pathname, int flags, int mode)
|
||||
{
|
||||
(void)mode;
|
||||
if (data == NULL || pathname == NULL) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we need to convert the pathname into FONTCHARACTER format with meta
|
||||
information inside (mainly the device) */
|
||||
uint16_t *fcpath = fs_path_normalize_fc(pathname);
|
||||
if (fcpath == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* handle open mode */
|
||||
int bfile_mode = BFile_ReadOnly;
|
||||
if(flags & O_WRONLY)
|
||||
bfile_mode = BFile_WriteOnly;
|
||||
else if(flags & O_RDWR)
|
||||
bfile_mode = BFile_ReadWrite;
|
||||
|
||||
/* Exclusive open means no sense unless creation is also requested */
|
||||
bool excl = (flags & O_EXCL) && (flags & O_CREAT);
|
||||
/* Truncation requires the file to be removed/recreated */
|
||||
bool trunc = (flags & O_TRUNC) && (flags & O_CREAT);
|
||||
|
||||
/* Stat the entry. A special case is needed for the root, which doesn't
|
||||
respond well. fs_path_normalize_fc() normalizes the path so we just
|
||||
have to check for the fixed string "\\fls0\". */
|
||||
bool exists;
|
||||
if(!memcmp(fcpath, u"\\\\fls0\\", 16)) {
|
||||
exists = true;
|
||||
type = BFile_Type_Directory;
|
||||
} else {
|
||||
exists = (BFile_Ext_Stat(fcpath, &type, NULL) == 0);
|
||||
if(!exists) type = -1;
|
||||
}
|
||||
|
||||
/* If the entry exists and O_EXCL was requested, fail. */
|
||||
if(exists && excl) {
|
||||
errno = EEXIST;
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* If the entry is not a directory but O_DIRECTORY is set, fail. If the
|
||||
directory doesn't exist, we fail regardless of O_CREAT. */
|
||||
if((flags & O_DIRECTORY) && type != BFile_Type_Directory) {
|
||||
errno = (exists ? ENOTDIR : ENOENT);
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* If the entry is a directory, open it as such */
|
||||
if(type == BFile_Type_Directory) {
|
||||
void *dp = fugue_dir_explore(path);
|
||||
fugue_descriptor_t data = {
|
||||
.type = &fugue_dir_descriptor_type,
|
||||
.data = dp,
|
||||
};
|
||||
fd = fugue_create_descriptor(&data);
|
||||
rc = fd;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Try and open the file normally, unless O_TRUNC is specified without
|
||||
O_EXCL, in which case we simply delete and recreate the file. */
|
||||
fugue_fd = BFile_EntryNotFound;
|
||||
if(trunc == 0)
|
||||
fugue_fd = BFile_Open(fcpath, bfile_mode);
|
||||
|
||||
/* If O_TRUNC is requested and either the file exists or we can create
|
||||
it, remove it. (If fugue_fd < 0 an opening error might still have
|
||||
occurred so we delete it just in case.) */
|
||||
if((flags & O_TRUNC) && (fugue_fd >= 0 || (flags & O_CREAT))) {
|
||||
if(fugue_fd >= 0)
|
||||
BFile_Close(fugue_fd);
|
||||
BFile_Remove(fcpath);
|
||||
fugue_fd = BFile_EntryNotFound;
|
||||
}
|
||||
|
||||
/* If the file does not exist and O_CREAT is set, create it */
|
||||
if((flags & O_CREAT) && ((flags & O_TRUNC) || fugue_fd < 0)) {
|
||||
new_file_size = 0;
|
||||
err = BFile_Create(fcpath, BFile_File, &new_file_size);
|
||||
if(err < 0) {
|
||||
errno = bfile_error_to_errno(err);
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
fugue_fd = BFile_Open(fcpath, bfile_mode);
|
||||
}
|
||||
|
||||
/* check error during hadling */
|
||||
if(fugue_fd < 0) {
|
||||
errno = bfile_error_to_errno(fugue_fd);
|
||||
rc = fugue_fd;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* If O_APPEND is set, move to the end of the file */
|
||||
// TODO: O_APPEND should move the cursor before *each* write
|
||||
int pos = 0;
|
||||
if((flags & O_APPEND)) {
|
||||
pos = BFile_Size(fugue_fd);
|
||||
BFile_Seek(fugue_fd, pos);
|
||||
}
|
||||
|
||||
/* Return the now-open file descriptor */
|
||||
fugue_fd_t *data = malloc(sizeof(fugue_fs_t));
|
||||
if(data == NULL) {
|
||||
BFile_Close(fugue_fd);
|
||||
goto end;
|
||||
}
|
||||
data->fd = fugue_fd;
|
||||
data->pos = pos;
|
||||
|
||||
/* generate file descriptor information */
|
||||
fugue_descriptor_t fd_data = {
|
||||
.type = &fugue_descriptor_type,
|
||||
.data = data,
|
||||
};
|
||||
rc = fd = fugue_create_descriptor(&fd_data);
|
||||
|
||||
if(fd == -1) {
|
||||
BFile_Close(fugue_fd);
|
||||
free(data);
|
||||
errno = ENFILE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
free(fcpath);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,8 @@
|
|||
#include <vhex/fs/fugue.h>
|
||||
|
||||
ssize_t fugue_write(void *data, const void *buf, size_t size)
|
||||
{
|
||||
(void)data;
|
||||
(void)buf;
|
||||
(void)size;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#include <vhex/fs/fugue.h>
|
||||
|
||||
ssize_t fugue_read(void *data, void *buf, size_t size)
|
||||
{
|
||||
(void)data;
|
||||
(void)buf;
|
||||
(void)size;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#include <vhex/fs.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
off_t lseek(int fd, off_t offset, int whence)
|
||||
{
|
||||
(void)fd;
|
||||
(void)offset;
|
||||
(void)whence;
|
||||
#if 0
|
||||
void *data;
|
||||
|
||||
errno = fs_table_find(&data, fd);
|
||||
if (errno != 0)
|
||||
return -1;
|
||||
|
||||
if (fd >= 0 && fd <= 2) {
|
||||
//TODO:support keyboard
|
||||
//TODO:support display
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fs_info.fs.primitives.lseek == NULL) {
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
return fs_info.fs.primitives.lseek(data, offset, whence);
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#include <vhex/fs.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* open() : try to open file */
|
||||
int open(const char *pathname, int flags, ...)
|
||||
{
|
||||
(void)pathname;
|
||||
(void)flags;
|
||||
#if 0
|
||||
va_list ap;
|
||||
void *data;
|
||||
int mode;
|
||||
|
||||
va_start(ap, flags);
|
||||
mode = va_arg(ap, int);
|
||||
va_end(ap);
|
||||
|
||||
if (fs_info.fs.primitives.open == NULL) {
|
||||
errno = ENOMEDIUM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = fs_table_reserve(&data);
|
||||
if (errno != 0)
|
||||
return -1;
|
||||
|
||||
return fs_info.fs.primitives.open(
|
||||
data,
|
||||
pathname,
|
||||
flags,
|
||||
mode
|
||||
);
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
#include <vhex/fs.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
ssize_t read(int fd, void *buf, size_t size)
|
||||
{
|
||||
(void)fd;
|
||||
(void)buf;
|
||||
(void)size;
|
||||
return -1;
|
||||
#if 0
|
||||
void *data;
|
||||
|
||||
errno = fs_table_find(&data, fd);
|
||||
if (errno != 0)
|
||||
return -1;
|
||||
|
||||
if (fd >= 0 && fd <= 2) {
|
||||
//TODO:support keyboard
|
||||
//TODO:support display
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fs_info.fs.primitives.read == NULL) {
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
return fs_info.fs.primitives.read(data, buf, size);
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
#include <vhex/fs.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
ssize_t write(int fd, const void *buf, size_t size)
|
||||
{
|
||||
(void)fd;
|
||||
(void)buf;
|
||||
(void)size;
|
||||
return -1;
|
||||
#if 0
|
||||
void *data;
|
||||
|
||||
errno = fs_table_find(&data, fd);
|
||||
if (errno != 0)
|
||||
return -1;
|
||||
|
||||
if (fd >= 0 && fd <= 2) {
|
||||
//TODO:support keyboard
|
||||
//TODO:support display
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fs_info.fs.primitives.write == NULL) {
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
return fs_info.fs.primitives.write(data, buf, size);
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
#include <vhex/rtc/interface.h>
|
||||
#include <vhex/rtc.h>
|
||||
#include <vhex/module.h>
|
||||
#include <vhex/driver.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* internal timer information */
|
||||
struct {
|
||||
struct rtc_drv_interface driver;
|
||||
} rtc_info;
|
||||
|
||||
//---
|
||||
// user-level timer API
|
||||
//---
|
||||
|
||||
/* rtc_get_time(): Read the current time from the RTC */
|
||||
int rtc_get_time(rtc_time_t *time)
|
||||
{
|
||||
if (rtc_info.driver.rtc_get_time != NULL)
|
||||
return rtc_info.driver.rtc_get_time(time);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* rtc_set_time(): Set current time in the RTC */
|
||||
int rtc_set_time(rtc_time_t const *time)
|
||||
{
|
||||
if (rtc_info.driver.rtc_set_time != NULL)
|
||||
return rtc_info.driver.rtc_set_time(time);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//---
|
||||
// Kernel module information
|
||||
//---
|
||||
|
||||
/* __rtc_init() : initialize the RTC module */
|
||||
static void __rtc_init(void)
|
||||
{
|
||||
memset(&rtc_info, 0x00, sizeof(rtc_info));
|
||||
|
||||
struct vhex_driver *driver = vhex_driver_table();
|
||||
for (int i = 0; i < vhex_driver_count(); ++i) {
|
||||
if (driver[i].flags.RTC) {
|
||||
memcpy(
|
||||
&rtc_info.driver,
|
||||
driver[i].module_data,
|
||||
sizeof(struct rtc_drv_interface)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* __rtc_quit() : uninitialize the RTC module */
|
||||
static void __rtc_quit(void)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
/* declare the timer module */
|
||||
|
||||
struct vhex_module mod_rtc = {
|
||||
.name = "RTC",
|
||||
.init = &__rtc_init,
|
||||
.quit = &__rtc_quit,
|
||||
};
|
||||
VHEX_DECLARE_MODULE(06, mod_rtc);
|
Loading…
Reference in New Issue