Begin implementing driver model.
This commit is contained in:
parent
3e888ffa65
commit
57ce078167
6
Makefile
6
Makefile
|
@ -6,9 +6,9 @@ TARGET := sentinel-65x-512K
|
||||||
all: build/$(TARGET).bin
|
all: build/$(TARGET).bin
|
||||||
|
|
||||||
include config/boot.mk
|
include config/boot.mk
|
||||||
include config/bios.mk
|
include config/kernel.mk
|
||||||
|
|
||||||
build/$(TARGET).bin: build/boot.bin build/bios.bin
|
build/$(TARGET).bin: build/boot.bin build/kernel.bin
|
||||||
#Create an empty .bin file.
|
#Create an empty .bin file.
|
||||||
@dd if=/dev/zero of=$@ bs=1024 count=512
|
@dd if=/dev/zero of=$@ bs=1024 count=512
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ build/$(TARGET).bin: build/boot.bin build/bios.bin
|
||||||
@dd if=build/boot.bin of=$@ bs=1024 seek=32 conv=notrunc
|
@dd if=build/boot.bin of=$@ bs=1024 seek=32 conv=notrunc
|
||||||
|
|
||||||
# Add the bios module at offset 0x008300
|
# Add the bios module at offset 0x008300
|
||||||
@dd if=build/bios.bin of=$@ bs=1 seek=33536 conv=notrunc
|
@dd if=build/kernel.bin of=$@ bs=1 seek=33536 conv=notrunc
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
BIOS_ASM_SRC := $(wildcard src/bios/*.s)
|
|
||||||
BIOS_C_SRC := $(wildcard src/bios/*.c)
|
|
||||||
|
|
||||||
BIOS_OBJ := $(BIOS_ASM_SRC:.s=.o)
|
|
||||||
BIOS_OBJ += $(BIOS_C_SRC:.c=.o)
|
|
||||||
|
|
||||||
BIOS_LDFLAGS := --list-file build/bios.lst
|
|
||||||
|
|
||||||
build/bios.bin: $(BIOS_OBJ)
|
|
||||||
echo "Linking $@..."
|
|
||||||
$(LD) -o $@ config/bios.scm $(LDFLAGS) $(BIOS_LDFLAGS) $^
|
|
||||||
mv build/bios.raw $@
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
KERNEL_ASM_SRC := $(wildcard src/kernel/*.s) \
|
||||||
|
$(wildcard src/kernel/*/*.s) \
|
||||||
|
$(wildcard src/kernel/*/*/*.s) \
|
||||||
|
$(wildcard src/kernel/*/*/*/*.s) \
|
||||||
|
$(wildcard src/kernel/*/*/*/*.s)
|
||||||
|
KERNEL_C_SRC := $(wildcard src/kernel/*.c) \
|
||||||
|
$(wildcard src/kernel/*/*.c) \
|
||||||
|
$(wildcard src/kernel/*/*/*.c) \
|
||||||
|
$(wildcard src/kernel/*/*/*/*.c) \
|
||||||
|
$(wildcard src/kernel/*/*/*/*/*.c)
|
||||||
|
|
||||||
|
KERNEL_OBJ := $(KERNEL_ASM_SRC:.s=.o)
|
||||||
|
KERNEL_OBJ += $(KERNEL_C_SRC:.c=.o)
|
||||||
|
|
||||||
|
KERNEL_LDFLAGS := --list-file build/kernel.lst
|
||||||
|
|
||||||
|
build/kernel.bin: $(KERNEL_OBJ)
|
||||||
|
echo "Linking $@..."
|
||||||
|
$(LD) -o $@ config/kernel.scm $(LDFLAGS) $(KERNEL_LDFLAGS) $^
|
||||||
|
mv build/kernel.raw $@
|
|
@ -5,17 +5,20 @@
|
||||||
(section zhuge)
|
(section zhuge)
|
||||||
(section znear)
|
(section znear)
|
||||||
(section zdata)
|
(section zdata)
|
||||||
|
(section huge)
|
||||||
(section heap)
|
(section heap)
|
||||||
)
|
)
|
||||||
|
|
||||||
(memory ROM
|
(memory ROM
|
||||||
(address (#xC08300 . #xC0FFFF))
|
(address (#xC08300 . #xC0FFFF))
|
||||||
(section code)
|
(section (code #xC08300))
|
||||||
(section farcode)
|
(section farcode)
|
||||||
(section cdata)
|
(section cdata)
|
||||||
(section switch)
|
(section switch)
|
||||||
(section near)
|
(section near)
|
||||||
(section data)
|
(section data)
|
||||||
|
(section chuge)
|
||||||
|
(section ihuge)
|
||||||
(section (irq_trampolines #xC0F000))
|
(section (irq_trampolines #xC0F000))
|
||||||
(section (irq_vectors #xC0FF80))
|
(section (irq_vectors #xC0FF80))
|
||||||
)
|
)
|
|
@ -1,10 +1,12 @@
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
//
|
//
|
||||||
// boot/w65c816s.h
|
// boot/w65c816s.h
|
||||||
// Assembly defines for the 65C816 architecture
|
// Defines for the 65C816 architecture
|
||||||
//
|
//
|
||||||
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
|
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
|
||||||
|
|
||||||
|
#ifdef __CALYPSI_ASSEMBLER__
|
||||||
|
|
||||||
#define native_mode \
|
#define native_mode \
|
||||||
clc \
|
clc \
|
||||||
xce
|
xce
|
||||||
|
@ -32,3 +34,5 @@
|
||||||
plx \
|
plx \
|
||||||
pla \
|
pla \
|
||||||
plp
|
plp
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,113 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// kernel/device.h
|
||||||
|
// Driver declarations.
|
||||||
|
//
|
||||||
|
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __CALYPSI_CC__
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// This symbol determines the maximum number of device drivers which
|
||||||
|
// can be in memory.
|
||||||
|
#ifndef DEVICE_MAX
|
||||||
|
#define DEVICE_MAX 32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// This symbol determines the maximum number of device map entries which
|
||||||
|
// ca be in memory.
|
||||||
|
#ifndef DEVICE_MAP_MAX
|
||||||
|
#define DEVICE_MAP_MAX 32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Forward declaration.
|
||||||
|
struct file;
|
||||||
|
|
||||||
|
// A device, in this context, is a code module which exposes a defined set
|
||||||
|
// of functions for interacting with files and file-like data. It is not specific
|
||||||
|
// as to the nature of the underlying data storage. It is equally valid for a
|
||||||
|
// device to use a block of RAM or a serial device as it is a hard drive
|
||||||
|
// or SD card.
|
||||||
|
//
|
||||||
|
// None of these functions are required to actually do anyting if it is not
|
||||||
|
// sensible for the kind of device being used; for example, it is not
|
||||||
|
// sensible for an inherently read-only device to support moving or
|
||||||
|
// renaming files.
|
||||||
|
typedef struct {
|
||||||
|
// Initialize the device.
|
||||||
|
int (*init)(void);
|
||||||
|
|
||||||
|
// Opens a file, given a pathname.
|
||||||
|
int (*open)(struct file *file);
|
||||||
|
|
||||||
|
// Closes an open file, given a unique ID.
|
||||||
|
int (*close)(struct file *file);
|
||||||
|
|
||||||
|
// Seeks within an open file, given a unique ID and a length.
|
||||||
|
int (*seek)(struct file *file, long length);
|
||||||
|
|
||||||
|
// Reads data from the specified file.
|
||||||
|
int (*read)(struct file *file, void *dest, size_t length);
|
||||||
|
|
||||||
|
// Writes data to the specified file.
|
||||||
|
int (*write)(struct file *file, void *src, size_t length);
|
||||||
|
|
||||||
|
// Perform driver-specific operations.
|
||||||
|
int (*ioctl)(struct file *file,
|
||||||
|
unsigned short operation,
|
||||||
|
void *arg);
|
||||||
|
|
||||||
|
// Creates the specified file given a pathname.
|
||||||
|
int (*create)(struct file *file);
|
||||||
|
|
||||||
|
// Copies the specified file using the specified names.
|
||||||
|
int (*copy)(struct file *src,
|
||||||
|
struct file *dest);
|
||||||
|
|
||||||
|
// Moves the specified file using the specified names.
|
||||||
|
int (*move)(struct file *src,
|
||||||
|
struct file *dest);
|
||||||
|
|
||||||
|
// Gets the size of the file.
|
||||||
|
int (*get_file_size)(struct file *file, size_t *size);
|
||||||
|
|
||||||
|
// Fills out the metadata in the specified file from the pathname
|
||||||
|
// in the provided file.
|
||||||
|
int (*init_file)(struct file *file);
|
||||||
|
} Device;
|
||||||
|
|
||||||
|
// The device map is a table that maps device names, such as SD0: or
|
||||||
|
// TTY2: to the device driver that manages the device.
|
||||||
|
struct device_map {
|
||||||
|
char *name;
|
||||||
|
unsigned short major_number;
|
||||||
|
unsigned short minor_number;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The global table of device drivers.
|
||||||
|
extern Device *device[DEVICE_MAX];
|
||||||
|
|
||||||
|
// The global map of device names to device modules.
|
||||||
|
extern struct device_map *device_map[DEVICE_MAP_MAX];
|
||||||
|
|
||||||
|
// Initialize all the device drivers. This is called once, at boot.
|
||||||
|
// It protects itself against being called again without a reset.
|
||||||
|
void device_init_all(void);
|
||||||
|
|
||||||
|
// Binds a device name to a device.
|
||||||
|
int device_bind_name(char *name,
|
||||||
|
unsigned short major_number,
|
||||||
|
unsigned short minor_number);
|
||||||
|
|
||||||
|
// Unbinds a bound device name.
|
||||||
|
int device_unbind_name(char *name);
|
||||||
|
|
||||||
|
// Get a bound device by its name.
|
||||||
|
int device_get_by_name(char *name, Device **device);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,12 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// kernel/device/null.h
|
||||||
|
// NULL driver declaration.
|
||||||
|
//
|
||||||
|
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "kernel/device.h"
|
||||||
|
|
||||||
|
extern Device NullDevice;
|
|
@ -0,0 +1,75 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// kernel/file.h
|
||||||
|
// File related declarations
|
||||||
|
//
|
||||||
|
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "kernel/device.h"
|
||||||
|
|
||||||
|
enum file_type {
|
||||||
|
FILE_TYPE_NORMAL,
|
||||||
|
FILE_TYPE_DIRECTORY,
|
||||||
|
FILE_TYPE_DEVICE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct file {
|
||||||
|
// The full path of the file, including its volume and basename.
|
||||||
|
char *pathname;
|
||||||
|
|
||||||
|
// The basename of the file. This usually points to
|
||||||
|
// the begining of the basename of the file in the
|
||||||
|
// pathname string.
|
||||||
|
char *basename;
|
||||||
|
|
||||||
|
// The type of the file.
|
||||||
|
enum file_type type;
|
||||||
|
|
||||||
|
bool open;
|
||||||
|
|
||||||
|
// Generic driver-specific data pointer
|
||||||
|
void *userdata;
|
||||||
|
|
||||||
|
// The major number identifies the device driver responsible for
|
||||||
|
// the file.
|
||||||
|
uint8_t major_number;
|
||||||
|
|
||||||
|
// The minor number identifies the device, among those the driver
|
||||||
|
// controls, which this file represents or is associated with.
|
||||||
|
uint8_t minor_number;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Using the pathname in the provided FCB, identify the device which manages
|
||||||
|
// the file and have that device populate the FCB.
|
||||||
|
int file_init(char *pathname, struct file *file);
|
||||||
|
|
||||||
|
int file_open(struct file *file);
|
||||||
|
|
||||||
|
// Closes an open file, given a unique ID.
|
||||||
|
int file_close(struct file *file);
|
||||||
|
|
||||||
|
// Seeks within an open file, given a unique ID and a length.
|
||||||
|
int file_seek(struct file *file, int32_t length);
|
||||||
|
|
||||||
|
// Reads data from the specified file.
|
||||||
|
int file_read(struct file *file, void *dest, size_t length);
|
||||||
|
|
||||||
|
// Writes data to the specified file.
|
||||||
|
int file_write(struct file *file, void *src, size_t length);
|
||||||
|
|
||||||
|
// Creates the specified file given a pathname.
|
||||||
|
int file_create(struct file *file);
|
||||||
|
|
||||||
|
// Copies the specified file using the specified names.
|
||||||
|
int file_copy(struct file *src, struct file *dest);
|
||||||
|
|
||||||
|
// Moves the specified file using the specified names.
|
||||||
|
int file_move(struct file *src, struct file *dest);
|
||||||
|
|
||||||
|
// Gets the size of the file.
|
||||||
|
int file_get_file_size(struct file *file, size_t *size);
|
|
@ -5,6 +5,8 @@
|
||||||
//
|
//
|
||||||
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
|
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#define CPU_SPEED_HZ 8000000
|
#define CPU_SPEED_HZ 8000000
|
||||||
#define UART3_BAUD_RATE 9600
|
#define UART3_BAUD_RATE 9600
|
||||||
#define UART3_TIMER_VALUE (CPU_SPEED_HZ / (16 * UART3_BAUD_RATE) - 1)
|
#define UART3_TIMER_VALUE (CPU_SPEED_HZ / (16 * UART3_BAUD_RATE) - 1)
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
//
|
//
|
||||||
// boot/vera.h
|
// boot/vera.h
|
||||||
// Assembly language defines for the VERA chip
|
// Defines for the VERA chip
|
||||||
//
|
//
|
||||||
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
|
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
|
||||||
|
|
||||||
|
#ifdef __CALYPSI_CC__
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define AUTO_NONE 0x000000
|
#define AUTO_NONE 0x000000
|
||||||
#define AUTO_INC_1 0x100000
|
#define AUTO_INC_1 0x100000
|
||||||
#define AUTO_INC_2 0x200000
|
#define AUTO_INC_2 0x200000
|
||||||
|
@ -122,3 +127,32 @@
|
||||||
#define VERA_PSG_BASE 0x01F9C0
|
#define VERA_PSG_BASE 0x01F9C0
|
||||||
#define VERA_PALETTE_BASE 0x01FA00
|
#define VERA_PALETTE_BASE 0x01FA00
|
||||||
#define VERA_SPRITE_ATTR_BASE 0x01FC00
|
#define VERA_SPRITE_ATTR_BASE 0x01FC00
|
||||||
|
|
||||||
|
// The assembler can't handle this stuff.
|
||||||
|
#ifdef __CALYPSI_CC__
|
||||||
|
|
||||||
|
void vera_set_address_0(uint32_t addr);
|
||||||
|
|
||||||
|
void vera_set_address_1(uint32_t addr);
|
||||||
|
|
||||||
|
uint8_t vera_read_data_reg_0(void);
|
||||||
|
|
||||||
|
uint8_t vera_read_data_reg_1(void);
|
||||||
|
|
||||||
|
uint16_t vera_read_data_reg(void);
|
||||||
|
|
||||||
|
void vera_write_data_reg_0(uint8_t new_value);
|
||||||
|
|
||||||
|
void vera_write_data_reg_1(uint8_t new_value);
|
||||||
|
|
||||||
|
void vera_write_data_reg(uint16_t new_value);
|
||||||
|
|
||||||
|
void vera_reset(void);
|
||||||
|
|
||||||
|
void vera_mem_read(void *dest, uint32_t src, size_t length);
|
||||||
|
|
||||||
|
void vera_mem_write(uint32_t dest, void *src, size_t length);
|
||||||
|
|
||||||
|
void vera_mem_set(uint32_t dest, uint8_t value, size_t length);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
//
|
//
|
||||||
// boot/w65c265s.h
|
// boot/w65c265s.h
|
||||||
// Assembly defines for the W65C265S chip
|
// Defines for the W65C265S chip
|
||||||
//
|
//
|
||||||
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
|
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
|
||||||
|
|
||||||
|
|
||||||
#define PD0 0x00DF00
|
#define PD0 0x00DF00
|
||||||
#define PD1 0x00DF01
|
#define PD1 0x00DF01
|
||||||
#define PD2 0x00DF02
|
#define PD2 0x00DF02
|
||||||
|
@ -87,6 +86,8 @@
|
||||||
#define PIR6 0x00DF7E
|
#define PIR6 0x00DF7E
|
||||||
#define PIR7 0x00DF7F
|
#define PIR7 0x00DF7F
|
||||||
|
|
||||||
|
#ifdef __CALYPSI_ASSEMBLER__
|
||||||
|
|
||||||
; Enable the 512 bytes of on-CPU SRAM from 0x000000-0001FF
|
; Enable the 512 bytes of on-CPU SRAM from 0x000000-0001FF
|
||||||
w65c265s_sram_on .macro
|
w65c265s_sram_on .macro
|
||||||
lda #0b00000100
|
lda #0b00000100
|
||||||
|
@ -126,4 +127,6 @@ fclk_stop .macro
|
||||||
fclk_select .macro
|
fclk_select .macro
|
||||||
lda #0b11111010
|
lda #0b11111010
|
||||||
tsb SSCR
|
tsb SSCR
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
#endif
|
Binary file not shown.
|
@ -1,35 +0,0 @@
|
||||||
FatFs License
|
|
||||||
|
|
||||||
FatFs has being developped as a personal project of the author, ChaN. It is
|
|
||||||
free from the code anyone else wrote at current release. Following code block
|
|
||||||
shows a copy of the FatFs license document that heading the source files.
|
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------/
|
|
||||||
/ FatFs - Generic FAT Filesystem Module Rx.xx /
|
|
||||||
/-----------------------------------------------------------------------------/
|
|
||||||
/
|
|
||||||
/ Copyright (C) 20xx, ChaN, all right reserved.
|
|
||||||
/
|
|
||||||
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
|
||||||
/ source and binary forms, with or without modification, are permitted provided
|
|
||||||
/ that the following condition is met:
|
|
||||||
/
|
|
||||||
/ 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
/ this condition and the following disclaimer.
|
|
||||||
/
|
|
||||||
/ This software is provided by the copyright holder and contributors "AS IS"
|
|
||||||
/ and any warranties related to this software are DISCLAIMED.
|
|
||||||
/ The copyright owner or contributors be NOT LIABLE for any damages caused
|
|
||||||
/ by use of this software.
|
|
||||||
/----------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
Therefore FatFs license is one of the BSD-style licenses, but there is a
|
|
||||||
significant feature. FatFs is mainly intended for embedded systems. In order to
|
|
||||||
extend the usability for commercial products, the redistributions of FatFs in
|
|
||||||
binary form, such as embedded code, binary library and any forms without source
|
|
||||||
code, do not need to include about FatFs in the documentations. This is
|
|
||||||
equivalent to the 1-clause BSD license. Of course FatFs is compatible with
|
|
||||||
the most of open source software licenses include GNU GPL. When you
|
|
||||||
redistribute the FatFs source code with changes or create a fork, the license
|
|
||||||
can also be changed to GNU GPL, BSD-style license or any open source software
|
|
||||||
license that not conflict with FatFs license.
|
|
|
@ -1,470 +0,0 @@
|
||||||
/*------------------------------------------------------------------------/
|
|
||||||
/ Foolproof MMCv3/SDv1/SDv2 (in SPI mode) control module
|
|
||||||
/-------------------------------------------------------------------------/
|
|
||||||
/
|
|
||||||
/ Copyright (C) 2019, ChaN, all right reserved.
|
|
||||||
/
|
|
||||||
/ * This software 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 products UNDER YOUR RESPONSIBILITY.
|
|
||||||
/ * Redistributions of source code must retain the above copyright notice.
|
|
||||||
/
|
|
||||||
/-------------------------------------------------------------------------/
|
|
||||||
Features and Limitations:
|
|
||||||
|
|
||||||
* No Media Change Detection
|
|
||||||
Application program needs to perform a f_mount() after media change.
|
|
||||||
|
|
||||||
/-------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "kernel/drivers/fatfs/ff.h" /* Obtains integer types for FatFs */
|
|
||||||
#include "kernel/drivers/fatfs/diskio.h" /* Common include file for FatFs and disk I/O layer */
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
|
||||||
/* Platform dependent macros and functions needed to be modified */
|
|
||||||
/*-------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*---------------------------------------------------------*/
|
|
||||||
/* User Provided RTC Function for FatFs module */
|
|
||||||
/*---------------------------------------------------------*/
|
|
||||||
/* This is a real time clock service to be called from */
|
|
||||||
/* FatFs module. Any valid time must be returned even if */
|
|
||||||
/* the system does not support an RTC. */
|
|
||||||
/* This function is not required in read-only cfg. */
|
|
||||||
|
|
||||||
// FIXME: Make this use the system RTC.
|
|
||||||
DWORD get_fattime (void)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Make this delay using a system timer.
|
|
||||||
static void
|
|
||||||
dly_us (int n)
|
|
||||||
{
|
|
||||||
(void) n;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
Module Private Functions
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/* MMC/SD command (SPI mode) */
|
|
||||||
#define CMD0 (0) /* GO_IDLE_STATE */
|
|
||||||
#define CMD1 (1) /* SEND_OP_COND */
|
|
||||||
#define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */
|
|
||||||
#define CMD8 (8) /* SEND_IF_COND */
|
|
||||||
#define CMD9 (9) /* SEND_CSD */
|
|
||||||
#define CMD10 (10) /* SEND_CID */
|
|
||||||
#define CMD12 (12) /* STOP_TRANSMISSION */
|
|
||||||
#define CMD13 (13) /* SEND_STATUS */
|
|
||||||
#define ACMD13 (0x80+13) /* SD_STATUS (SDC) */
|
|
||||||
#define CMD16 (16) /* SET_BLOCKLEN */
|
|
||||||
#define CMD17 (17) /* READ_SINGLE_BLOCK */
|
|
||||||
#define CMD18 (18) /* READ_MULTIPLE_BLOCK */
|
|
||||||
#define CMD23 (23) /* SET_BLOCK_COUNT */
|
|
||||||
#define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
|
|
||||||
#define CMD24 (24) /* WRITE_BLOCK */
|
|
||||||
#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */
|
|
||||||
#define CMD32 (32) /* ERASE_ER_BLK_START */
|
|
||||||
#define CMD33 (33) /* ERASE_ER_BLK_END */
|
|
||||||
#define CMD38 (38) /* ERASE */
|
|
||||||
#define CMD55 (55) /* APP_CMD */
|
|
||||||
#define CMD58 (58) /* READ_OCR */
|
|
||||||
|
|
||||||
|
|
||||||
static
|
|
||||||
DSTATUS Stat = STA_NOINIT; /* Disk status */
|
|
||||||
|
|
||||||
static
|
|
||||||
BYTE CardType; /* b0:MMC, b1:SDv1, b2:SDv2, b3:Block addressing */
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* Transmit bytes to the card */
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
// FIXME: Make this use VERA.
|
|
||||||
static
|
|
||||||
void xmit_mmc (const BYTE* buff, UINT count)
|
|
||||||
{
|
|
||||||
(void) buff;
|
|
||||||
(void) count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* Receive bytes from the card */
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
// FIXME: Make this use VERA.
|
|
||||||
static
|
|
||||||
void rcvr_mmc (BYTE *buff, UINT count)
|
|
||||||
{
|
|
||||||
(void) buff;
|
|
||||||
(void) count;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* Wait for card ready */
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
static
|
|
||||||
int wait_ready (void) /* 1:OK, 0:Timeout */
|
|
||||||
{
|
|
||||||
BYTE d;
|
|
||||||
UINT tmr;
|
|
||||||
|
|
||||||
|
|
||||||
for (tmr = 5000; tmr; tmr--) { /* Wait for ready in timeout of 500ms */
|
|
||||||
rcvr_mmc(&d, 1);
|
|
||||||
if (d == 0xFF) break;
|
|
||||||
dly_us(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tmr ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* Deselect the card and release SPI bus */
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
// FIXME: Make this use VERA.
|
|
||||||
static
|
|
||||||
void deselect (void)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* Select the card and wait for ready */
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
// FIXME: Make this use VERA.
|
|
||||||
static
|
|
||||||
int select (void) /* 1:OK, 0:Timeout */
|
|
||||||
{
|
|
||||||
return 0; /* Failed */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* Receive a data packet from the card */
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
static
|
|
||||||
int rcvr_datablock ( /* 1:OK, 0:Failed */
|
|
||||||
BYTE *buff, /* Data buffer to store received data */
|
|
||||||
UINT btr /* Byte count */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
BYTE d[2];
|
|
||||||
UINT tmr;
|
|
||||||
|
|
||||||
|
|
||||||
for (tmr = 1000; tmr; tmr--) { /* Wait for data packet in timeout of 100ms */
|
|
||||||
rcvr_mmc(d, 1);
|
|
||||||
if (d[0] != 0xFF) break;
|
|
||||||
dly_us(100);
|
|
||||||
}
|
|
||||||
if (d[0] != 0xFE) return 0; /* If not valid data token, return with error */
|
|
||||||
|
|
||||||
rcvr_mmc(buff, btr); /* Receive the data block into buffer */
|
|
||||||
rcvr_mmc(d, 2); /* Discard CRC */
|
|
||||||
|
|
||||||
return 1; /* Return with success */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* Send a data packet to the card */
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
static
|
|
||||||
int xmit_datablock ( /* 1:OK, 0:Failed */
|
|
||||||
const BYTE *buff, /* 512 byte data block to be transmitted */
|
|
||||||
BYTE token /* Data/Stop token */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
BYTE d[2];
|
|
||||||
|
|
||||||
|
|
||||||
if (!wait_ready()) return 0;
|
|
||||||
|
|
||||||
d[0] = token;
|
|
||||||
xmit_mmc(d, 1); /* Xmit a token */
|
|
||||||
if (token != 0xFD) { /* Is it data token? */
|
|
||||||
xmit_mmc(buff, 512); /* Xmit the 512 byte data block to MMC */
|
|
||||||
rcvr_mmc(d, 2); /* Xmit dummy CRC (0xFF,0xFF) */
|
|
||||||
rcvr_mmc(d, 1); /* Receive data response */
|
|
||||||
if ((d[0] & 0x1F) != 0x05) /* If not accepted, return with error */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* Send a command packet to the card */
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
static
|
|
||||||
BYTE send_cmd ( /* Returns command response (bit7==1:Send failed)*/
|
|
||||||
BYTE cmd, /* Command byte */
|
|
||||||
DWORD arg /* Argument */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
BYTE n, d, buf[6];
|
|
||||||
|
|
||||||
|
|
||||||
if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
|
|
||||||
cmd &= 0x7F;
|
|
||||||
n = send_cmd(CMD55, 0);
|
|
||||||
if (n > 1) return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Select the card and wait for ready except to stop multiple block read */
|
|
||||||
if (cmd != CMD12) {
|
|
||||||
deselect();
|
|
||||||
if (!select()) return 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send a command packet */
|
|
||||||
buf[0] = 0x40 | cmd; /* Start + Command index */
|
|
||||||
buf[1] = (BYTE)(arg >> 24); /* Argument[31..24] */
|
|
||||||
buf[2] = (BYTE)(arg >> 16); /* Argument[23..16] */
|
|
||||||
buf[3] = (BYTE)(arg >> 8); /* Argument[15..8] */
|
|
||||||
buf[4] = (BYTE)arg; /* Argument[7..0] */
|
|
||||||
n = 0x01; /* Dummy CRC + Stop */
|
|
||||||
if (cmd == CMD0) n = 0x95; /* (valid CRC for CMD0(0)) */
|
|
||||||
if (cmd == CMD8) n = 0x87; /* (valid CRC for CMD8(0x1AA)) */
|
|
||||||
buf[5] = n;
|
|
||||||
xmit_mmc(buf, 6);
|
|
||||||
|
|
||||||
/* Receive command response */
|
|
||||||
if (cmd == CMD12) rcvr_mmc(&d, 1); /* Skip a stuff byte when stop reading */
|
|
||||||
n = 10; /* Wait for a valid response in timeout of 10 attempts */
|
|
||||||
do
|
|
||||||
rcvr_mmc(&d, 1);
|
|
||||||
while ((d & 0x80) && --n);
|
|
||||||
|
|
||||||
return d; /* Return with the response value */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
Public Functions
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* Get Disk Status */
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
DSTATUS disk_status (
|
|
||||||
BYTE drv /* Drive number (always 0) */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (drv) return STA_NOINIT;
|
|
||||||
|
|
||||||
return Stat;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* Initialize Disk Drive */
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
DSTATUS disk_initialize (
|
|
||||||
BYTE drv /* Physical drive nmuber (0) */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
BYTE n, ty, cmd, buf[4];
|
|
||||||
UINT tmr;
|
|
||||||
DSTATUS s;
|
|
||||||
|
|
||||||
|
|
||||||
if (drv) return RES_NOTRDY;
|
|
||||||
|
|
||||||
dly_us(10000); /* 10ms */
|
|
||||||
|
|
||||||
for (n = 10; n; n--) rcvr_mmc(buf, 1); /* Apply 80 dummy clocks and the card gets ready to receive command */
|
|
||||||
|
|
||||||
ty = 0;
|
|
||||||
if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */
|
|
||||||
if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */
|
|
||||||
rcvr_mmc(buf, 4); /* Get trailing return value of R7 resp */
|
|
||||||
if (buf[2] == 0x01 && buf[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
|
|
||||||
for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state (ACMD41 with HCS bit) */
|
|
||||||
if (send_cmd(ACMD41, 1UL << 30) == 0) break;
|
|
||||||
dly_us(1000);
|
|
||||||
}
|
|
||||||
if (tmr && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
|
|
||||||
rcvr_mmc(buf, 4);
|
|
||||||
ty = (buf[0] & 0x40) ? CT_SDC2 | CT_BLOCK : CT_SDC2; /* SDv2+ */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else { /* SDv1 or MMCv3 */
|
|
||||||
if (send_cmd(ACMD41, 0) <= 1) {
|
|
||||||
ty = CT_SDC2; cmd = ACMD41; /* SDv1 */
|
|
||||||
} else {
|
|
||||||
ty = CT_MMC3; cmd = CMD1; /* MMCv3 */
|
|
||||||
}
|
|
||||||
for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state */
|
|
||||||
if (send_cmd(cmd, 0) == 0) break;
|
|
||||||
dly_us(1000);
|
|
||||||
}
|
|
||||||
if (!tmr || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */
|
|
||||||
ty = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CardType = ty;
|
|
||||||
s = ty ? 0 : STA_NOINIT;
|
|
||||||
Stat = s;
|
|
||||||
|
|
||||||
deselect();
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* Read Sector(s) */
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
DRESULT disk_read (
|
|
||||||
BYTE drv, /* Physical drive nmuber (0) */
|
|
||||||
BYTE *buff, /* Pointer to the data buffer to store read data */
|
|
||||||
LBA_t sector, /* Start sector number (LBA) */
|
|
||||||
UINT count /* Sector count (1..128) */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
BYTE cmd;
|
|
||||||
DWORD sect = (DWORD)sector;
|
|
||||||
|
|
||||||
|
|
||||||
if (disk_status(drv) & STA_NOINIT) return RES_NOTRDY;
|
|
||||||
if (!(CardType & CT_BLOCK)) sect *= 512; /* Convert LBA to byte address if needed */
|
|
||||||
|
|
||||||
cmd = count > 1 ? CMD18 : CMD17; /* READ_MULTIPLE_BLOCK : READ_SINGLE_BLOCK */
|
|
||||||
if (send_cmd(cmd, sect) == 0) {
|
|
||||||
do {
|
|
||||||
if (!rcvr_datablock(buff, 512)) break;
|
|
||||||
buff += 512;
|
|
||||||
} while (--count);
|
|
||||||
if (cmd == CMD18) send_cmd(CMD12, 0); /* STOP_TRANSMISSION */
|
|
||||||
}
|
|
||||||
deselect();
|
|
||||||
|
|
||||||
return count ? RES_ERROR : RES_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* Write Sector(s) */
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
DRESULT disk_write (
|
|
||||||
BYTE drv, /* Physical drive nmuber (0) */
|
|
||||||
const BYTE *buff, /* Pointer to the data to be written */
|
|
||||||
LBA_t sector, /* Start sector number (LBA) */
|
|
||||||
UINT count /* Sector count (1..128) */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
DWORD sect = (DWORD)sector;
|
|
||||||
|
|
||||||
|
|
||||||
if (disk_status(drv) & STA_NOINIT) return RES_NOTRDY;
|
|
||||||
//if (!(CardType & CT_BLOCK)) sect *= 512; /* Convert LBA to byte address if needed */
|
|
||||||
|
|
||||||
if (count == 1) { /* Single block write */
|
|
||||||
if ((send_cmd(CMD24, sect) == 0) /* WRITE_BLOCK */
|
|
||||||
&& xmit_datablock(buff, 0xFE))
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
else { /* Multiple block write */
|
|
||||||
if (CardType & CT_SDC) send_cmd(ACMD23, count);
|
|
||||||
if (send_cmd(CMD25, sect) == 0) { /* WRITE_MULTIPLE_BLOCK */
|
|
||||||
do {
|
|
||||||
if (!xmit_datablock(buff, 0xFC)) break;
|
|
||||||
buff += 512;
|
|
||||||
} while (--count);
|
|
||||||
if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */
|
|
||||||
count = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deselect();
|
|
||||||
|
|
||||||
return count ? RES_ERROR : RES_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* Miscellaneous Functions */
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
DRESULT disk_ioctl (
|
|
||||||
BYTE drv, /* Physical drive nmuber (0) */
|
|
||||||
BYTE ctrl, /* Control code */
|
|
||||||
void *buff /* Buffer to send/receive control data */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
DRESULT res;
|
|
||||||
BYTE n, csd[16];
|
|
||||||
DWORD cs;
|
|
||||||
|
|
||||||
|
|
||||||
if (disk_status(drv) & STA_NOINIT) return RES_NOTRDY; /* Check if card is in the socket */
|
|
||||||
|
|
||||||
res = RES_ERROR;
|
|
||||||
switch (ctrl) {
|
|
||||||
case CTRL_SYNC : /* Make sure that no pending write process */
|
|
||||||
if (select()) res = RES_OK;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */
|
|
||||||
if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
|
|
||||||
if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
|
|
||||||
cs = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1;
|
|
||||||
*(LBA_t*)buff = cs << 10;
|
|
||||||
} else { /* SDC ver 1.XX or MMC */
|
|
||||||
n = (BYTE)((csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2);
|
|
||||||
cs = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
|
|
||||||
*(LBA_t*)buff = cs << (n - 9);
|
|
||||||
}
|
|
||||||
res = RES_OK;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */
|
|
||||||
*(DWORD*)buff = 128;
|
|
||||||
res = RES_OK;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
res = RES_PARERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
deselect();
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
7083
src/bdos/fs/ff.c
7083
src/bdos/fs/ff.c
File diff suppressed because it is too large
Load Diff
|
@ -1,207 +0,0 @@
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* A Sample Code of User Provided OS Dependent Functions for FatFs */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "kernel/drivers/fatfs/ff.h"
|
|
||||||
|
|
||||||
|
|
||||||
#if FF_USE_LFN == 3 /* Use dynamic memory allocation */
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* Allocate/Free a Memory Block */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "stdlib.h" /* with POSIX API */
|
|
||||||
|
|
||||||
|
|
||||||
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */
|
|
||||||
UINT msize /* Number of bytes to allocate */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return malloc((size_t)msize); /* Allocate a new memory block */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ff_memfree (
|
|
||||||
void* mblock /* Pointer to the memory block to free (no effect if null) */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
free(mblock); /* Free the memory block */
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if FF_FS_REENTRANT /* Mutal exclusion */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* Definitions of Mutex */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#define OS_TYPE 0 /* 0:Win32, 1:uITRON4.0, 2:uC/OS-II, 3:FreeRTOS, 4:CMSIS-RTOS */
|
|
||||||
|
|
||||||
|
|
||||||
#if OS_TYPE == 0 /* Win32 */
|
|
||||||
#include <windows.h>
|
|
||||||
static HANDLE Mutex[FF_VOLUMES + 1]; /* Table of mutex handle */
|
|
||||||
|
|
||||||
#elif OS_TYPE == 1 /* uITRON */
|
|
||||||
#include "itron.h"
|
|
||||||
#include "kernel.h"
|
|
||||||
static mtxid Mutex[FF_VOLUMES + 1]; /* Table of mutex ID */
|
|
||||||
|
|
||||||
#elif OS_TYPE == 2 /* uc/OS-II */
|
|
||||||
#include "includes.h"
|
|
||||||
static OS_EVENT *Mutex[FF_VOLUMES + 1]; /* Table of mutex pinter */
|
|
||||||
|
|
||||||
#elif OS_TYPE == 3 /* FreeRTOS */
|
|
||||||
#include "FreeRTOS.h"
|
|
||||||
#include "semphr.h"
|
|
||||||
static SemaphoreHandle_t Mutex[FF_VOLUMES + 1]; /* Table of mutex handle */
|
|
||||||
|
|
||||||
#elif OS_TYPE == 4 /* CMSIS-RTOS */
|
|
||||||
#include "cmsis_os.h"
|
|
||||||
static osMutexId Mutex[FF_VOLUMES + 1]; /* Table of mutex ID */
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* Create a Mutex */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* This function is called in f_mount function to create a new mutex
|
|
||||||
/ or semaphore for the volume. When a 0 is returned, the f_mount function
|
|
||||||
/ fails with FR_INT_ERR.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int ff_mutex_create ( /* Returns 1:Function succeeded or 0:Could not create the mutex */
|
|
||||||
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
#if OS_TYPE == 0 /* Win32 */
|
|
||||||
Mutex[vol] = CreateMutex(NULL, FALSE, NULL);
|
|
||||||
return (int)(Mutex[vol] != INVALID_HANDLE_VALUE);
|
|
||||||
|
|
||||||
#elif OS_TYPE == 1 /* uITRON */
|
|
||||||
T_CMTX cmtx = {TA_TPRI,1};
|
|
||||||
|
|
||||||
Mutex[vol] = acre_mtx(&cmtx);
|
|
||||||
return (int)(Mutex[vol] > 0);
|
|
||||||
|
|
||||||
#elif OS_TYPE == 2 /* uC/OS-II */
|
|
||||||
OS_ERR err;
|
|
||||||
|
|
||||||
Mutex[vol] = OSMutexCreate(0, &err);
|
|
||||||
return (int)(err == OS_NO_ERR);
|
|
||||||
|
|
||||||
#elif OS_TYPE == 3 /* FreeRTOS */
|
|
||||||
Mutex[vol] = xSemaphoreCreateMutex();
|
|
||||||
return (int)(Mutex[vol] != NULL);
|
|
||||||
|
|
||||||
#elif OS_TYPE == 4 /* CMSIS-RTOS */
|
|
||||||
osMutexDef(cmsis_os_mutex);
|
|
||||||
|
|
||||||
Mutex[vol] = osMutexCreate(osMutex(cmsis_os_mutex));
|
|
||||||
return (int)(Mutex[vol] != NULL);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* Delete a Mutex */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* This function is called in f_mount function to delete a mutex or
|
|
||||||
/ semaphore of the volume created with ff_mutex_create function.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ff_mutex_delete ( /* Returns 1:Function succeeded or 0:Could not delete due to an error */
|
|
||||||
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
#if OS_TYPE == 0 /* Win32 */
|
|
||||||
CloseHandle(Mutex[vol]);
|
|
||||||
|
|
||||||
#elif OS_TYPE == 1 /* uITRON */
|
|
||||||
del_mtx(Mutex[vol]);
|
|
||||||
|
|
||||||
#elif OS_TYPE == 2 /* uC/OS-II */
|
|
||||||
OS_ERR err;
|
|
||||||
|
|
||||||
OSMutexDel(Mutex[vol], OS_DEL_ALWAYS, &err);
|
|
||||||
|
|
||||||
#elif OS_TYPE == 3 /* FreeRTOS */
|
|
||||||
vSemaphoreDelete(Mutex[vol]);
|
|
||||||
|
|
||||||
#elif OS_TYPE == 4 /* CMSIS-RTOS */
|
|
||||||
osMutexDelete(Mutex[vol]);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* Request a Grant to Access the Volume */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* This function is called on enter file functions to lock the volume.
|
|
||||||
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int ff_mutex_take ( /* Returns 1:Succeeded or 0:Timeout */
|
|
||||||
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
#if OS_TYPE == 0 /* Win32 */
|
|
||||||
return (int)(WaitForSingleObject(Mutex[vol], FF_FS_TIMEOUT) == WAIT_OBJECT_0);
|
|
||||||
|
|
||||||
#elif OS_TYPE == 1 /* uITRON */
|
|
||||||
return (int)(tloc_mtx(Mutex[vol], FF_FS_TIMEOUT) == E_OK);
|
|
||||||
|
|
||||||
#elif OS_TYPE == 2 /* uC/OS-II */
|
|
||||||
OS_ERR err;
|
|
||||||
|
|
||||||
OSMutexPend(Mutex[vol], FF_FS_TIMEOUT, &err));
|
|
||||||
return (int)(err == OS_NO_ERR);
|
|
||||||
|
|
||||||
#elif OS_TYPE == 3 /* FreeRTOS */
|
|
||||||
return (int)(xSemaphoreTake(Mutex[vol], FF_FS_TIMEOUT) == pdTRUE);
|
|
||||||
|
|
||||||
#elif OS_TYPE == 4 /* CMSIS-RTOS */
|
|
||||||
return (int)(osMutexWait(Mutex[vol], FF_FS_TIMEOUT) == osOK);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* Release a Grant to Access the Volume */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* This function is called on leave file functions to unlock the volume.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ff_mutex_give (
|
|
||||||
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
#if OS_TYPE == 0 /* Win32 */
|
|
||||||
ReleaseMutex(Mutex[vol]);
|
|
||||||
|
|
||||||
#elif OS_TYPE == 1 /* uITRON */
|
|
||||||
unl_mtx(Mutex[vol]);
|
|
||||||
|
|
||||||
#elif OS_TYPE == 2 /* uC/OS-II */
|
|
||||||
OSMutexPost(Mutex[vol]);
|
|
||||||
|
|
||||||
#elif OS_TYPE == 3 /* FreeRTOS */
|
|
||||||
xSemaphoreGive(Mutex[vol]);
|
|
||||||
|
|
||||||
#elif OS_TYPE == 4 /* CMSIS-RTOS */
|
|
||||||
osMutexRelease(Mutex[vol]);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* FF_FS_REENTRANT */
|
|
15592
src/bdos/fs/ffunicode.c
15592
src/bdos/fs/ffunicode.c
File diff suppressed because it is too large
Load Diff
|
@ -1,13 +0,0 @@
|
||||||
//*****************************************************************************
|
|
||||||
// 65X-DOS
|
|
||||||
//
|
|
||||||
// src/bdos/main.c
|
|
||||||
//*****************************************************************************
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
void
|
|
||||||
main(void)
|
|
||||||
{
|
|
||||||
for (;;) {}
|
|
||||||
}
|
|
|
@ -50,4 +50,4 @@ delay_y
|
||||||
sta PCS7
|
sta PCS7
|
||||||
|
|
||||||
// And we are booted enough to jump to high ROM.
|
// And we are booted enough to jump to high ROM.
|
||||||
jmp 0xC00000
|
jmp long:0xC08300
|
|
@ -0,0 +1,122 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// kernel/device.c
|
||||||
|
// Device drivers.
|
||||||
|
//
|
||||||
|
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "kernel/device.h"
|
||||||
|
#include "kernel/file.h"
|
||||||
|
|
||||||
|
static bool device_init_all_run = false;
|
||||||
|
|
||||||
|
Device *device[DEVICE_MAX] = {
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
struct device_map *device_map[DEVICE_MAP_MAX] = {0};
|
||||||
|
|
||||||
|
static short get_lowest_free_device(void);
|
||||||
|
|
||||||
|
void device_init_all(void)
|
||||||
|
{
|
||||||
|
if (device_init_all_run == true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < DEVICE_MAX; i += 1) {
|
||||||
|
if (device[i] != NULL) {
|
||||||
|
if (device[i]->init != NULL) {
|
||||||
|
device[i]->init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
device_init_all_run = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int device_bind_name(char *name,
|
||||||
|
unsigned short major_number,
|
||||||
|
unsigned short minor_number)
|
||||||
|
{
|
||||||
|
if (name == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// It is not permissible to have the same name attached to two
|
||||||
|
// devices.
|
||||||
|
for (int i = 0; i < DEVICE_MAP_MAX; i += 1) {
|
||||||
|
if (strcmp(device_map[i]->name, name) == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
short device_index = get_lowest_free_device();
|
||||||
|
if (device_index == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *device_name = strdup(name);
|
||||||
|
if (name == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
device_map[device_index] = calloc(1, sizeof(struct device_map));
|
||||||
|
if (device_map[device_index] == NULL) {
|
||||||
|
free(device_name);
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
device_map[device_index]->major_number = major_number;
|
||||||
|
device_map[device_index]->minor_number = minor_number;
|
||||||
|
device_map[device_index]->name = device_name;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int device_unbind_name(char *name)
|
||||||
|
{
|
||||||
|
if (name == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < DEVICE_MAP_MAX; i += 1) {
|
||||||
|
if (strcmp(device_map[i]->name, name) == 0) {
|
||||||
|
free(device_map[i]->name);
|
||||||
|
free(device_map[i]);
|
||||||
|
device_map[i] = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int device_get_by_name(char *name, Device **device)
|
||||||
|
{
|
||||||
|
if (name == NULL || device == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < DEVICE_MAP_MAX; i += 1) {
|
||||||
|
if (strcmp(device_map[i]->name, name) == 0) {
|
||||||
|
unsigned short major_number = device_map[i]->major_number;
|
||||||
|
*device = device[major_number];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static short get_lowest_free_device(void)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < DEVICE_MAP_MAX; i += 1) {
|
||||||
|
if (device_map[i] == NULL) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// kernel/device/null.c
|
||||||
|
// NULL device implementation.
|
||||||
|
//
|
||||||
|
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "kernel/device/null.h"
|
||||||
|
#include "kernel/device.h"
|
||||||
|
#include "kernel/file.h"
|
||||||
|
|
||||||
|
static int null_init(void);
|
||||||
|
|
||||||
|
static int null_open(struct file *file);
|
||||||
|
|
||||||
|
static int null_close(struct file *file);
|
||||||
|
|
||||||
|
static int null_read(struct file *file, void *dest, size_t length);
|
||||||
|
|
||||||
|
static int null_write(struct file *file, void *src, size_t length);
|
||||||
|
|
||||||
|
static int null_get_file_size(struct file *file, size_t *size);
|
||||||
|
|
||||||
|
static int null_init_file(struct file *file);
|
||||||
|
|
||||||
|
Device NullDevice = {
|
||||||
|
.init = null_init,
|
||||||
|
.open = null_open,
|
||||||
|
.close = null_close,
|
||||||
|
.read = null_read,
|
||||||
|
.write = null_write,
|
||||||
|
.get_file_size = null_get_file_size,
|
||||||
|
.init_file = null_init_file
|
||||||
|
};
|
||||||
|
|
||||||
|
static int null_init(void)
|
||||||
|
{
|
||||||
|
device_bind_name("zero", 0, 0);
|
||||||
|
device_bind_name("null", 0, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int null_open(struct file *file)
|
||||||
|
{
|
||||||
|
switch (file->minor_number) {
|
||||||
|
case 0 ... 1:
|
||||||
|
file->open = true;
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int null_close(struct file *file)
|
||||||
|
{
|
||||||
|
switch (file->minor_number) {
|
||||||
|
case 0 ... 1:
|
||||||
|
file->open = false;
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int null_read(struct file *file,
|
||||||
|
void *dest,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
if (file->open == false) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (file->minor_number) {
|
||||||
|
case 0:
|
||||||
|
memset(dest, 0x00, length);
|
||||||
|
return length;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int null_write(struct file *file,
|
||||||
|
void *src,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
if (file->open == false) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) src;
|
||||||
|
if (file->minor_number != 1) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int null_get_file_size(struct file *file,
|
||||||
|
size_t *size)
|
||||||
|
{
|
||||||
|
switch (file->minor_number) {
|
||||||
|
case 0 ... 1:
|
||||||
|
*size = 0;
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int null_init_file(struct file *file)
|
||||||
|
{
|
||||||
|
if (file->major_number != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (file->minor_number) {
|
||||||
|
case 0 ... 1:
|
||||||
|
file->open = false;
|
||||||
|
file->type = FILE_TYPE_DEVICE;
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// kernel/file.c
|
||||||
|
// File definitions.
|
||||||
|
//
|
||||||
|
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "kernel/file.h"
|
||||||
|
#include "kernel/device.h"
|
||||||
|
|
||||||
|
// Using the pathname string, identify the major/minor device for
|
||||||
|
// the file, and have that device initialize the file control
|
||||||
|
// block.
|
||||||
|
int file_init(char *pathname, struct file *file)
|
||||||
|
{
|
||||||
|
// First thing, we need to identify the device. The pathname
|
||||||
|
// is to be fully-qualified; this means it must have the
|
||||||
|
// device name, followed by a colon, followed by an optional
|
||||||
|
// file path. If the file path part is empty, then the file
|
||||||
|
// refers to the device itself. We perform the identification
|
||||||
|
// by first copying the pathname, then tokenizing the copy on
|
||||||
|
// the ":" character. The first token must be a string which
|
||||||
|
// matches a registered device in the device map.
|
||||||
|
// Then we populate the located major and minor numbers and copy
|
||||||
|
// the pathname into the FCB, and pass it along to the device
|
||||||
|
// driver for more initialization.
|
||||||
|
|
||||||
|
char *path = strdup(pathname);
|
||||||
|
if (path == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *dev = strtok(path, ":");
|
||||||
|
|
||||||
|
for (unsigned short i = 0; i < DEVICE_MAP_MAX; i += 1) {
|
||||||
|
if (strcmp(dev, device_map[i]->name) == 0) {
|
||||||
|
file->pathname = strdup(pathname);
|
||||||
|
free(path);
|
||||||
|
|
||||||
|
if (file->pathname == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
file->major_number = device_map[i]->major_number;
|
||||||
|
file->minor_number = device_map[i]->minor_number;
|
||||||
|
|
||||||
|
return device[file->major_number]->init_file(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(path);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -12,15 +12,29 @@
|
||||||
// DP[6] for the Y register.
|
// DP[6] for the Y register.
|
||||||
extern uint16_t Dp[4];
|
extern uint16_t Dp[4];
|
||||||
|
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wunused-parameter"
|
||||||
|
|
||||||
|
void cop_handler(uint16_t arg_c, uint16_t arg_x, uint16_t arg_y) {
|
||||||
|
switch (arg_c & 0x00FF) {
|
||||||
|
case 0:
|
||||||
|
//soft_reset();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//cop_error_invalid_call();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void irq_handler(void) {
|
void irq_handler(void) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void brk_irq_handler(void) {
|
void brk_handler(void) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void abort_irq_handler(void) {
|
void abort_handler(void) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,10 +138,4 @@ void uart_3_tx_irq_handler(void) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cop_handler(uint16_t arg_c, uint16_t arg_x, uint16_t arg_y) {
|
#pragma clang diagnostic pop
|
||||||
(void) arg_c;
|
|
||||||
(void) arg_x;
|
|
||||||
(void) arg_y;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
.extern _Dp
|
.extern _Dp
|
||||||
|
|
||||||
.extern irq_handler
|
.extern irq_handler
|
||||||
|
.extern cop_handler
|
||||||
|
|
||||||
; This section gets copied to 0x00F000
|
; This section gets copied to 0x00F000
|
||||||
.section irq_trampolines
|
.section irq_trampolines
|
||||||
|
@ -251,11 +252,17 @@ uart_3_tx_irq:
|
||||||
cop_irq:
|
cop_irq:
|
||||||
phb
|
phb
|
||||||
phd
|
phd
|
||||||
rep #0b00110000
|
rep #0b00110000
|
||||||
pha
|
stx _Dp+4
|
||||||
phx
|
sty _Dp+6
|
||||||
phy
|
call cop_handler
|
||||||
jump interrupt_return
|
rep #0b00110000
|
||||||
|
lda _Dp+0
|
||||||
|
ldx _Dp+4
|
||||||
|
ldy _Dp+6
|
||||||
|
pld
|
||||||
|
plb
|
||||||
|
rti
|
||||||
|
|
||||||
brk_irq:
|
brk_irq:
|
||||||
phb
|
phb
|
|
@ -5,6 +5,10 @@
|
||||||
//
|
//
|
||||||
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
|
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
|
||||||
|
|
||||||
|
#include "kernel/device.h"
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
|
device_init_all();
|
||||||
|
|
||||||
for (;;) {}
|
for (;;) {}
|
||||||
}
|
}
|
Loading…
Reference in New Issue