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
|
||||
|
||||
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.
|
||||
@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
|
||||
|
||||
# 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
|
||||
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 znear)
|
||||
(section zdata)
|
||||
(section huge)
|
||||
(section heap)
|
||||
)
|
||||
|
||||
(memory ROM
|
||||
(address (#xC08300 . #xC0FFFF))
|
||||
(section code)
|
||||
(section (code #xC08300))
|
||||
(section farcode)
|
||||
(section cdata)
|
||||
(section switch)
|
||||
(section near)
|
||||
(section data)
|
||||
(section chuge)
|
||||
(section ihuge)
|
||||
(section (irq_trampolines #xC0F000))
|
||||
(section (irq_vectors #xC0FF80))
|
||||
)
|
|
@ -1,10 +1,12 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// boot/w65c816s.h
|
||||
// Assembly defines for the 65C816 architecture
|
||||
// Defines for the 65C816 architecture
|
||||
//
|
||||
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
|
||||
|
||||
#ifdef __CALYPSI_ASSEMBLER__
|
||||
|
||||
#define native_mode \
|
||||
clc \
|
||||
xce
|
||||
|
@ -32,3 +34,5 @@
|
|||
plx \
|
||||
pla \
|
||||
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>
|
||||
|
||||
#pragma once
|
||||
|
||||
#define CPU_SPEED_HZ 8000000
|
||||
#define UART3_BAUD_RATE 9600
|
||||
#define UART3_TIMER_VALUE (CPU_SPEED_HZ / (16 * UART3_BAUD_RATE) - 1)
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// boot/vera.h
|
||||
// Assembly language defines for the VERA chip
|
||||
// Defines for the VERA chip
|
||||
//
|
||||
// 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_INC_1 0x100000
|
||||
#define AUTO_INC_2 0x200000
|
||||
|
@ -122,3 +127,32 @@
|
|||
#define VERA_PSG_BASE 0x01F9C0
|
||||
#define VERA_PALETTE_BASE 0x01FA00
|
||||
#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
|
||||
//
|
||||
// boot/w65c265s.h
|
||||
// Assembly defines for the W65C265S chip
|
||||
// Defines for the W65C265S chip
|
||||
//
|
||||
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
|
||||
|
||||
|
||||
#define PD0 0x00DF00
|
||||
#define PD1 0x00DF01
|
||||
#define PD2 0x00DF02
|
||||
|
@ -87,6 +86,8 @@
|
|||
#define PIR6 0x00DF7E
|
||||
#define PIR7 0x00DF7F
|
||||
|
||||
#ifdef __CALYPSI_ASSEMBLER__
|
||||
|
||||
; Enable the 512 bytes of on-CPU SRAM from 0x000000-0001FF
|
||||
w65c265s_sram_on .macro
|
||||
lda #0b00000100
|
||||
|
@ -126,4 +127,6 @@ fclk_stop .macro
|
|||
fclk_select .macro
|
||||
lda #0b11111010
|
||||
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
|
||||
|
||||
// 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.
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
|
||||
void brk_irq_handler(void) {
|
||||
void brk_handler(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
void abort_irq_handler(void) {
|
||||
void abort_handler(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -124,10 +138,4 @@ void uart_3_tx_irq_handler(void) {
|
|||
return;
|
||||
}
|
||||
|
||||
void cop_handler(uint16_t arg_c, uint16_t arg_x, uint16_t arg_y) {
|
||||
(void) arg_c;
|
||||
(void) arg_x;
|
||||
(void) arg_y;
|
||||
return;
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
|
@ -16,6 +16,7 @@
|
|||
.extern _Dp
|
||||
|
||||
.extern irq_handler
|
||||
.extern cop_handler
|
||||
|
||||
; This section gets copied to 0x00F000
|
||||
.section irq_trampolines
|
||||
|
@ -251,11 +252,17 @@ uart_3_tx_irq:
|
|||
cop_irq:
|
||||
phb
|
||||
phd
|
||||
rep #0b00110000
|
||||
pha
|
||||
phx
|
||||
phy
|
||||
jump interrupt_return
|
||||
rep #0b00110000
|
||||
stx _Dp+4
|
||||
sty _Dp+6
|
||||
call cop_handler
|
||||
rep #0b00110000
|
||||
lda _Dp+0
|
||||
ldx _Dp+4
|
||||
ldy _Dp+6
|
||||
pld
|
||||
plb
|
||||
rti
|
||||
|
||||
brk_irq:
|
||||
phb
|
|
@ -5,6 +5,10 @@
|
|||
//
|
||||
// Copyright © 2024 Kyle J Cardoza <Kyle.Cardoza@icloud.com>
|
||||
|
||||
#include "kernel/device.h"
|
||||
|
||||
void main(void) {
|
||||
device_init_all();
|
||||
|
||||
for (;;) {}
|
||||
}
|
Loading…
Reference in New Issue