mirror of
https://github.com/mist-devel/mist-firmware.git
synced 2026-05-03 23:09:45 +00:00
Firmware import
This commit is contained in:
135
AT91SAM7S256-ROM.ld
Normal file
135
AT91SAM7S256-ROM.ld
Normal file
@@ -0,0 +1,135 @@
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*- ATMEL Microcontroller Software Support - ROUSSET - */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* The software is delivered "AS IS" without warranty or condition of any */
|
||||
/* kind, either express, implied or statutory. This includes without */
|
||||
/* limitation any warranty or condition with respect to merchantability or */
|
||||
/* fitness for any particular purpose, or against the infringements of */
|
||||
/* intellectual property rights of others. */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*- File source : GCC_FLASH.ld */
|
||||
/*- Object : Linker Script File for Flash Workspace */
|
||||
/*- Compilation flag : None */
|
||||
/*- */
|
||||
/*- 1.0 11/Mar/05 JPP : Creation S256 */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
24-02-2006 Ewout Boks. Adapted from AT91SAM7S64-RAM.ld script by M. Thomas.
|
||||
- Changed the memory sections to model the AT91SAM7S256 .
|
||||
- tested succesfully with AT91SAM7 GPIO Example and PEEDI debugger
|
||||
on AT91SAM7S-EK equipped with AT91SAM7S256
|
||||
*/
|
||||
|
||||
/* Memory Definitions */
|
||||
|
||||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x00100000, LENGTH = 0x00040000
|
||||
DATA (rw) : ORIGIN = 0x00200000, LENGTH = 0x00010000
|
||||
STACK (rw) : ORIGIN = 0x00210000, LENGTH = 0x00000000
|
||||
}
|
||||
|
||||
|
||||
/* Section Definitions */
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* first section is .text which is used for code */
|
||||
. = 0x0000000;
|
||||
.text : { *Cstartup.o (.text) }>FLASH =0
|
||||
.text :
|
||||
{
|
||||
*(.text) /* remaining code */
|
||||
|
||||
*(.glue_7t) *(.glue_7)
|
||||
|
||||
} >FLASH
|
||||
|
||||
. = ALIGN(4);
|
||||
|
||||
/* .rodata section which is used for read-only data (constants) */
|
||||
|
||||
.rodata :
|
||||
{
|
||||
*(.rodata)
|
||||
} >FLASH
|
||||
|
||||
. = ALIGN(4);
|
||||
|
||||
_etext = . ;
|
||||
PROVIDE (etext = .);
|
||||
|
||||
/* .data section which is used for initialized data */
|
||||
|
||||
.data : AT (_etext)
|
||||
{
|
||||
_data = . ;
|
||||
*(.data)
|
||||
SORT(CONSTRUCTORS)
|
||||
. = ALIGN(4);
|
||||
*(.ramsection) /* "RAM-Functions" */ /* added by mthomas */
|
||||
} >DATA
|
||||
. = ALIGN(4);
|
||||
|
||||
_edata = . ;
|
||||
PROVIDE (edata = .);
|
||||
|
||||
/* .bss section which is used for uninitialized data */
|
||||
|
||||
.bss :
|
||||
{
|
||||
__bss_start = . ;
|
||||
__bss_start__ = . ;
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
}
|
||||
. = ALIGN(4);
|
||||
__bss_end__ = . ;
|
||||
__end__ = . ;
|
||||
_end = .;
|
||||
PROVIDE (end = .);
|
||||
|
||||
. = ALIGN(4);
|
||||
.int_data :
|
||||
{
|
||||
*(.internal_ram_top)
|
||||
}> STACK
|
||||
|
||||
|
||||
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to the beginning
|
||||
of the section so we begin them at 0. */
|
||||
/* DWARF 1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
/* GNU DWARF 1 extensions */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
/* DWARF 1.1 and DWARF 2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
/* DWARF 2 */
|
||||
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
/* SGI/MIPS DWARF 2 extensions */
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
|
||||
}
|
||||
2233
AT91SAM7S256.h
Normal file
2233
AT91SAM7S256.h
Normal file
File diff suppressed because it is too large
Load Diff
302
Cstartup.S
Normal file
302
Cstartup.S
Normal file
@@ -0,0 +1,302 @@
|
||||
/*------------------------------------------------------------------------------
|
||||
//*- ATMEL Microcontroller Software Support - ROUSSET -
|
||||
//*------------------------------------------------------------------------------
|
||||
//* The software is delivered "AS IS" without warranty or condition of any
|
||||
//* kind, either express, implied or statutory. This includes without
|
||||
//* limitation any warranty or condition with respect to merchantability or
|
||||
//* fitness for any particular purpose, or against the infringements of
|
||||
//* intellectual property rights of others.
|
||||
//*-----------------------------------------------------------------------------
|
||||
//*- File source : Cstartup.s
|
||||
//*- Object : Generic CStartup for KEIL and GCC No Use REMAP
|
||||
//*- Compilation flag : None
|
||||
//*-
|
||||
//*- 1.0 10/Mar/05 JPP : Creation
|
||||
//*- 1.1 01/Apr/05 JPP : save SPSR
|
||||
//*-----------------------------------------------------------------------------*/
|
||||
|
||||
.equ IRQ_Stack_Size, 0x00000060
|
||||
|
||||
/* #include "AT91SAM7S256_inc.h" */
|
||||
|
||||
.equ AIC_IVR, (256)
|
||||
.equ AIC_FVR, (260)
|
||||
.equ AIC_EOICR, (304)
|
||||
.equ AT91C_BASE_AIC, (0xFFFFF000)
|
||||
|
||||
#;------------------------------------------------------------------------------
|
||||
#;- Section Definition
|
||||
#;-----------------
|
||||
#;- Section
|
||||
#;- .internal_ram_top Top_Stack: used by the cstartup for vector initalisation
|
||||
#;- management defined by ld and affect from ldscript
|
||||
#;------------------------------------------------------------------------------
|
||||
.section .internal_ram_top
|
||||
.code 32
|
||||
.align 0
|
||||
.global Top_Stack
|
||||
Top_Stack:
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
*- Area Definition
|
||||
*------------------------------------------------------------------------------
|
||||
* .text is used instead of .section .text so it works with arm-aout too. */
|
||||
.section .reset
|
||||
.text
|
||||
.global _startup
|
||||
.func _startup
|
||||
_startup:
|
||||
reset:
|
||||
/*------------------------------------------------------------------------------
|
||||
//*- Exception vectors
|
||||
//*--------------------
|
||||
//*- These vectors can be read at address 0 or at RAM address
|
||||
//*- They ABSOLUTELY requires to be in relative addresssing mode in order to
|
||||
//*- guarantee a valid jump. For the moment, all are just looping.
|
||||
//*- If an exception occurs before remap, this would result in an infinite loop.
|
||||
//*- To ensure if a exeption occurs before start application to infinite loop.
|
||||
//*------------------------------------------------------------------------------*/
|
||||
|
||||
B InitReset /* 0x00 Reset handler */
|
||||
undefvec:
|
||||
B undefvec /* 0x04 Undefined Instruction */
|
||||
swivec:
|
||||
B swivec /* 0x08 Software Interrupt */
|
||||
pabtvec:
|
||||
B pabtvec /* 0x0C Prefetch Abort */
|
||||
dabtvec:
|
||||
B dabtvec /* 0x10 Data Abort */
|
||||
rsvdvec:
|
||||
B rsvdvec /* 0x14 reserved */
|
||||
irqvec:
|
||||
B IRQ_Handler_Entry /* 0x18 IRQ */
|
||||
fiqvec: /* 0x1c FIQ */
|
||||
/*------------------------------------------------------------------------------
|
||||
//*- Function : FIQ_Handler_Entry
|
||||
//*- Treatments : FIQ Controller Interrupt Handler.
|
||||
//*- Called Functions : AIC_FVR[interrupt]
|
||||
//*------------------------------------------------------------------------------*/
|
||||
|
||||
FIQ_Handler_Entry:
|
||||
|
||||
/*- Switch in SVC/User Mode to allow User Stack access for C code */
|
||||
/* because the FIQ is not yet acknowledged*/
|
||||
|
||||
/*- Save and r0 in FIQ_Register */
|
||||
mov r9,r0
|
||||
ldr r0 , [r8, #AIC_FVR]
|
||||
msr CPSR_c,#I_BIT | F_BIT | ARM_MODE_SVC
|
||||
|
||||
/*- Save scratch/used registers and LR in User Stack */
|
||||
stmfd sp!, { r1-r3, r12, lr}
|
||||
|
||||
/*- Branch to the routine pointed by the AIC_FVR */
|
||||
mov r14, pc
|
||||
bx r0
|
||||
|
||||
/*- Restore scratch/used registers and LR from User Stack */
|
||||
ldmia sp!, { r1-r3, r12, lr}
|
||||
|
||||
/*- Leave Interrupts disabled and switch back in FIQ mode */
|
||||
msr CPSR_c, #I_BIT | F_BIT | ARM_MODE_FIQ
|
||||
|
||||
/*- Restore the R0 ARM_MODE_SVC register */
|
||||
mov r0,r9
|
||||
|
||||
/*- Restore the Program Counter using the LR_fiq directly in the PC */
|
||||
subs pc,lr,#4
|
||||
.align 0
|
||||
.RAM_TOP:
|
||||
.word Top_Stack
|
||||
|
||||
InitReset:
|
||||
/*------------------------------------------------------------------------------
|
||||
/*- Low level Init (PMC, AIC, ? ....) by C function AT91F_LowLevelInit
|
||||
/*------------------------------------------------------------------------------*/
|
||||
.extern AT91F_LowLevelInit
|
||||
/*- minumum C initialization */
|
||||
/*- call AT91F_LowLevelInit( void) */
|
||||
|
||||
ldr r13,.RAM_TOP /* temporary stack in internal RAM */
|
||||
/*--Call Low level init function in ABSOLUTE through the Interworking */
|
||||
ldr r0,=AT91F_LowLevelInit
|
||||
mov lr, pc
|
||||
bx r0
|
||||
/*------------------------------------------------------------------------------
|
||||
//*- Stack Sizes Definition
|
||||
//*------------------------
|
||||
//*- Interrupt Stack requires 2 words x 8 priority level x 4 bytes when using
|
||||
//*- the vectoring. This assume that the IRQ management.
|
||||
//*- The Interrupt Stack must be adjusted depending on the interrupt handlers.
|
||||
//*- Fast Interrupt not requires stack If in your application it required you must
|
||||
//*- be definehere.
|
||||
//*- The System stack size is not defined and is limited by the free internal
|
||||
//*- SRAM.
|
||||
//*------------------------------------------------------------------------------*/
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
//*- Top of Stack Definition
|
||||
//*-------------------------
|
||||
//*- Interrupt and Supervisor Stack are located at the top of internal memory in
|
||||
//*- order to speed the exception handling context saving and restoring.
|
||||
//*- ARM_MODE_SVC (Application, C) Stack is located at the top of the external memory.
|
||||
//*------------------------------------------------------------------------------*/
|
||||
|
||||
.EQU IRQ_STACK_SIZE, (3*8*4)
|
||||
.EQU ARM_MODE_FIQ, 0x11
|
||||
.EQU ARM_MODE_IRQ, 0x12
|
||||
.EQU ARM_MODE_SVC, 0x13
|
||||
|
||||
.EQU I_BIT, 0x80
|
||||
.EQU F_BIT, 0x40
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
//*- Setup the stack for each mode
|
||||
//*-------------------------------*/
|
||||
mov r0,r13
|
||||
|
||||
/*- Set up Fast Interrupt Mode and set FIQ Mode Stack*/
|
||||
msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT
|
||||
/*- Init the FIQ register*/
|
||||
ldr r8, =AT91C_BASE_AIC
|
||||
|
||||
/*- Set up Interrupt Mode and set IRQ Mode Stack*/
|
||||
msr CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT
|
||||
mov r13, r0 /* Init stack IRQ */
|
||||
sub r0, r0, #IRQ_Stack_Size
|
||||
/*- Set up Supervisor Mode and set Supervisor Mode Stack*/
|
||||
msr CPSR_c, #ARM_MODE_SVC
|
||||
mov r13, r0 /* Init stack Sup */
|
||||
|
||||
/*- Enable interrupt & Set up Supervisor Mode and set Supervisor Mode Stack*/
|
||||
|
||||
# Relocate .data section (Copy from ROM to RAM)
|
||||
LDR R1, =_etext
|
||||
LDR R2, =_data
|
||||
LDR R3, =_edata
|
||||
LoopRel: CMP R2, R3
|
||||
LDRLO R0, [R1], #4
|
||||
STRLO R0, [R2], #4
|
||||
BLO LoopRel
|
||||
|
||||
# Clear .bss section (Zero init)
|
||||
MOV R0, #0
|
||||
LDR R1, =__bss_start__
|
||||
LDR R2, =__bss_end__
|
||||
LoopZI: CMP R1, R2
|
||||
STRLO R0, [R1], #4
|
||||
BLO LoopZI
|
||||
|
||||
ldr lr,=exit
|
||||
ldr r0,=main
|
||||
bx r0
|
||||
|
||||
.size _startup, . - _startup
|
||||
.endfunc
|
||||
|
||||
|
||||
/* "exit" dummy added by mthomas to avoid sbrk write read etc. needed
|
||||
by the newlib default "exit" */
|
||||
.global exit
|
||||
.func exit
|
||||
exit:
|
||||
b .
|
||||
.size exit, . - exit
|
||||
.endfunc
|
||||
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
//*- Manage exception
|
||||
//*---------------
|
||||
//*- This module The exception must be ensure in ARM mode
|
||||
//*------------------------------------------------------------------------------
|
||||
//*------------------------------------------------------------------------------
|
||||
//*- Function : IRQ_Handler_Entry
|
||||
//*- Treatments : IRQ Controller Interrupt Handler.
|
||||
//*- Called Functions : AIC_IVR[interrupt]
|
||||
//*------------------------------------------------------------------------------*/
|
||||
.global IRQ_Handler_Entry
|
||||
.func IRQ_Handler_Entry
|
||||
|
||||
IRQ_Handler_Entry:
|
||||
|
||||
/*- Manage Exception Entry */
|
||||
/*- Adjust and save LR_irq in IRQ stack */
|
||||
sub lr, lr, #4
|
||||
stmfd sp!, {lr}
|
||||
|
||||
/*- Save SPSR need to be saved for nested interrupt */
|
||||
mrs r14, SPSR
|
||||
stmfd sp!, {r14}
|
||||
|
||||
/*- Save and r0 in IRQ stack */
|
||||
stmfd sp!, {r0}
|
||||
|
||||
/*- Write in the IVR to support Protect Mode */
|
||||
/*- No effect in Normal Mode */
|
||||
/*- De-assert the NIRQ and clear the source in Protect Mode */
|
||||
ldr r14, =AT91C_BASE_AIC
|
||||
ldr r0 , [r14, #AIC_IVR]
|
||||
str r14, [r14, #AIC_IVR]
|
||||
|
||||
/*- Enable Interrupt and Switch in Supervisor Mode */
|
||||
msr CPSR_c, #ARM_MODE_SVC
|
||||
|
||||
/*- Save scratch/used registers and LR in User Stack */
|
||||
stmfd sp!, { r1-r3, r12, r14}
|
||||
|
||||
/*- Branch to the routine pointed by the AIC_IVR */
|
||||
mov r14, pc
|
||||
bx r0
|
||||
/*- Restore scratch/used registers and LR from User Stack*/
|
||||
ldmia sp!, { r1-r3, r12, r14}
|
||||
|
||||
/*- Disable Interrupt and switch back in IRQ mode */
|
||||
msr CPSR_c, #I_BIT | ARM_MODE_IRQ
|
||||
|
||||
/*- Mark the End of Interrupt on the AIC */
|
||||
ldr r14, =AT91C_BASE_AIC
|
||||
str r14, [r14, #AIC_EOICR]
|
||||
|
||||
/*- Restore SPSR_irq and r0 from IRQ stack */
|
||||
ldmia sp!, {r0}
|
||||
|
||||
/*- Restore SPSR_irq and r0 from IRQ stack */
|
||||
ldmia sp!, {r14}
|
||||
msr SPSR_cxsf, r14
|
||||
|
||||
/*- Restore adjusted LR_irq from IRQ stack directly in the PC */
|
||||
ldmia sp!, {pc}^
|
||||
|
||||
.size IRQ_Handler_Entry, . - IRQ_Handler_Entry
|
||||
.endfunc
|
||||
/*---------------------------------------------------------------
|
||||
//* ?EXEPTION_VECTOR
|
||||
//* This module is only linked if needed for closing files.
|
||||
//*---------------------------------------------------------------*/
|
||||
.global AT91F_Default_FIQ_handler
|
||||
.func AT91F_Default_FIQ_handler
|
||||
AT91F_Default_FIQ_handler:
|
||||
b AT91F_Default_FIQ_handler
|
||||
.size AT91F_Default_FIQ_handler, . - AT91F_Default_FIQ_handler
|
||||
.endfunc
|
||||
|
||||
.global AT91F_Default_IRQ_handler
|
||||
.func AT91F_Default_IRQ_handler
|
||||
AT91F_Default_IRQ_handler:
|
||||
b AT91F_Default_IRQ_handler
|
||||
.size AT91F_Default_IRQ_handler, . - AT91F_Default_IRQ_handler
|
||||
.endfunc
|
||||
|
||||
.global AT91F_Spurious_handler
|
||||
.func AT91F_Spurious_handler
|
||||
AT91F_Spurious_handler:
|
||||
b AT91F_Spurious_handler
|
||||
.size AT91F_Spurious_handler, . - AT91F_Spurious_handler
|
||||
.endfunc
|
||||
|
||||
|
||||
.end
|
||||
|
||||
|
||||
83
Cstartup_SAM7.c
Normal file
83
Cstartup_SAM7.c
Normal file
@@ -0,0 +1,83 @@
|
||||
//*----------------------------------------------------------------------------
|
||||
//* ATMEL Microcontroller Software Support - ROUSSET -
|
||||
//*----------------------------------------------------------------------------
|
||||
//* The software is delivered "AS IS" without warranty or condition of any
|
||||
//* kind, either express, implied or statutory. This includes without
|
||||
//* limitation any warranty or condition with respect to merchantability or
|
||||
//* fitness for any particular purpose, or against the infringements of
|
||||
//* intellectual property rights of others.
|
||||
//*----------------------------------------------------------------------------
|
||||
//* File Name : Cstartup_SAM7.c
|
||||
//* Object : Low level initializations written in C for GCC Tools
|
||||
//* Creation : 12/Jun/04
|
||||
//* 1.2 28/Feb/05 JPP : LIB change AT91C_WDTC_WDDIS & PLL
|
||||
//* 1.3 21/Mar/05 JPP : Change PLL Wait time
|
||||
//*----------------------------------------------------------------------------
|
||||
|
||||
// Include the board file description
|
||||
#include "AT91SAM7S256.h"
|
||||
|
||||
// The following functions must be write in ARM mode this function called directly
|
||||
// by exception vector
|
||||
extern void AT91F_Spurious_handler(void);
|
||||
extern void AT91F_Default_IRQ_handler(void);
|
||||
extern void AT91F_Default_FIQ_handler(void);
|
||||
|
||||
//*----------------------------------------------------------------------------
|
||||
//* \fn AT91F_LowLevelInit
|
||||
//* \brief This function performs very low level HW initialization
|
||||
//* this function can be use a Stack, depending the compilation
|
||||
//* optimization mode
|
||||
//*----------------------------------------------------------------------------
|
||||
void AT91F_LowLevelInit( void)
|
||||
{
|
||||
int i;
|
||||
AT91PS_PMC pPMC = AT91C_BASE_PMC;
|
||||
//* Set Flash Waite sate
|
||||
// Single Cycle Access at Up to 30 MHz, or 40
|
||||
// if MCK = 47923200 I have 50 Cycle for 1 usecond ( flied MC_FMR->FMCN
|
||||
AT91C_BASE_MC->MC_FMR = ((AT91C_MC_FMCN)&(48 <<16)) | AT91C_MC_FWS_1FWS ;
|
||||
|
||||
//* Watchdog Disable
|
||||
AT91C_BASE_WDTC->WDTC_WDMR= AT91C_WDTC_WDDIS;
|
||||
|
||||
//* Set MCK at 47 923 200
|
||||
// 1 Enabling the Main Oscillator:
|
||||
// SCK = 1/32768 = 30.51 uSecond
|
||||
// Start up time = 8 * 6 / SCK = 56 * 30.51 = 1,46484375 ms
|
||||
pPMC->PMC_MOR = ( (AT91C_CKGR_OSCOUNT) & (0x06 <<8)) | AT91C_CKGR_MOSCEN ;
|
||||
// Wait the startup time
|
||||
while(!(pPMC->PMC_SR & AT91C_PMC_MOSCS));
|
||||
// 2 Checking the Main Oscillator Frequency (Optional)
|
||||
// 3 Setting PLL and divider:
|
||||
// - div by 5 Fin = 3,6864 =(18,432 / 5)
|
||||
// - Mul 25+1: Fout = 95,8464 =(3,6864 *26)
|
||||
// for 96 MHz the erroe is 0.16%
|
||||
// Field out NOT USED = 0
|
||||
// PLLCOUNT pll startup time estimate at : 0.844 ms
|
||||
// PLLCOUNT 28 = 0.000844 /(1/32768)
|
||||
pPMC->PMC_PLLR = ((AT91C_CKGR_DIV & 0x05) |
|
||||
(AT91C_CKGR_PLLCOUNT & (28<<8)) |
|
||||
(AT91C_CKGR_MUL & (25<<16)));
|
||||
|
||||
// Wait the startup time
|
||||
while(!(pPMC->PMC_SR & AT91C_PMC_LOCK));
|
||||
while(!(pPMC->PMC_SR & AT91C_PMC_MCKRDY));
|
||||
// 4. Selection of Master Clock and Processor Clock
|
||||
// select the PLL clock divided by 2
|
||||
pPMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2 ;
|
||||
while(!(pPMC->PMC_SR & AT91C_PMC_MCKRDY));
|
||||
|
||||
pPMC->PMC_MCKR |= AT91C_PMC_CSS_PLL_CLK ;
|
||||
while(!(pPMC->PMC_SR & AT91C_PMC_MCKRDY));
|
||||
|
||||
// Set up the default interrupts handler vectors
|
||||
AT91C_BASE_AIC->AIC_SVR[0] = (int) AT91F_Default_FIQ_handler ;
|
||||
for (i=1;i < 31; i++)
|
||||
{
|
||||
AT91C_BASE_AIC->AIC_SVR[i] = (int) AT91F_Default_IRQ_handler ;
|
||||
}
|
||||
AT91C_BASE_AIC->AIC_SPU = (int) AT91F_Spurious_handler ;
|
||||
|
||||
}
|
||||
|
||||
87
Makefile
Normal file
87
Makefile
Normal file
@@ -0,0 +1,87 @@
|
||||
BASE ?= /opt/arm-none-eabi/bin/arm-none-eabi
|
||||
CC = $(BASE)-gcc
|
||||
LD = $(BASE)-gcc
|
||||
AS = $(BASE)-as
|
||||
CP = $(BASE)-objcopy
|
||||
DUMP = $(BASE)-objdump
|
||||
|
||||
TODAY = `date +"%m/%d/%y"`
|
||||
|
||||
PRJ = firmware
|
||||
SRC = Cstartup_SAM7.c fat.c fdd.c firmware.c fpga.c hardware.c hdd.c main.c menu.c mmc.c osd.c syscalls.c user_io.c boot_print.c boot_logo.c rafile.c config.c tos.c
|
||||
SRC += usb/max3421e.c usb/usb.c usb/hub.c usb/hid.c usb/timer.c
|
||||
OBJ = $(SRC:.c=.o)
|
||||
|
||||
LINKMAP = AT91SAM7S256-ROM.ld
|
||||
LIBDIR =
|
||||
|
||||
# Commandline options for each tool.
|
||||
CFLAGS = -I. -Iusb -c -fno-common -O3 -DMIST -fsigned-char -DVDATE=\"`date +"%y%m%d"`\"
|
||||
AFLAGS = -ahls -mapcs-32
|
||||
LFLAGS = -nostartfiles -Wl,-Map,$(PRJ).map -T$(LINKMAP) $(LIBDIR)
|
||||
CPFLAGS = --output-target=ihex
|
||||
|
||||
MKUPG = mkupg
|
||||
|
||||
# Libraries.
|
||||
LIBS =
|
||||
|
||||
# Our target.
|
||||
all: $(PRJ).hex $(PRJ).upg
|
||||
|
||||
clean:
|
||||
rm -f *.o *.hex *.elf *.map *.lst core *~ */*.o $(MKUPG) *.bin *.upg
|
||||
|
||||
reset:
|
||||
openocd -f interface/olimex-arm-usb-tiny-h.cfg -f target/at91sam7sx.cfg --command "adapter_khz 10000; init; reset init; resume; shutdown"
|
||||
|
||||
unprotect:
|
||||
openocd -f interface/olimex-arm-usb-tiny-h.cfg -f target/at91sam7sx.cfg --command "adapter_khz 10000; init; reset init; flash protect 0 0 7 off; resume; shutdown"
|
||||
|
||||
$(MKUPG): $(MKUPG).c
|
||||
gcc -o $@ $<
|
||||
|
||||
flash: $(PRJ).bin
|
||||
openocd -f interface/olimex-arm-usb-tiny-h.cfg -f target/at91sam7sx.cfg --command "adapter_khz 10000; init; reset init; flash protect 0 0 7 off; sleep 1; arm7_9 fast_memory_access enable; flash write_bank 0 $(PRJ).bin 0x0; resume; shutdown"
|
||||
|
||||
flash_ul: $(PRJ).bin
|
||||
openocd -f interface/ulink.cfg -f target/at91sam7sx.cfg --command "adapter_khz 10000; init; reset init; flash protect 0 0 7 off; sleep 1; arm7_9 fast_memory_access enable; flash write_bank 0 $(PRJ).bin 0x0; resume; shutdown"
|
||||
|
||||
flash_sam: $(PRJ).hex
|
||||
Sam_I_Am -x flash_sam_i_am
|
||||
|
||||
# Convert ELF binary to bin file.
|
||||
$(PRJ).bin: $(PRJ).elf
|
||||
$(CP) -O binary $< $@
|
||||
|
||||
# Convert ELF binary to Intel HEX file.
|
||||
$(PRJ).hex: $(PRJ).elf
|
||||
$(CP) $(CPFLAGS) $< $@
|
||||
|
||||
# Link - this produces an ELF binary.
|
||||
$(PRJ).elf: crt.o $(OBJ)
|
||||
$(LD) $(LFLAGS) -o $@ $+ $(LIBS)
|
||||
|
||||
$(PRJ).upg: $(PRJ).bin $(MKUPG)
|
||||
./$(MKUPG) $< $@ `date +"%y%m%d"`
|
||||
|
||||
# Compile the C runtime.
|
||||
crt.o: Cstartup.S
|
||||
$(AS) $(AFLAGS) -o $@ $< > crt.lst
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
sections: $(PRJ).elf
|
||||
$(DUMP) --section-headers $<
|
||||
|
||||
release:
|
||||
make clean
|
||||
make $(PRJ).hex $(PRJ).bin $(PRJ).upg
|
||||
rm ../../www/firmware*.zip
|
||||
zip ../../www/firmware.zip $(PRJ).hex $(PRJ).bin $(PRJ).upg logo.raw
|
||||
make clean
|
||||
cd ..; zip -urq ../www/firmware_src.zip minimig -x '*/.svn/*' '*.old' '*.new'
|
||||
cp ../../www/files.html files.tmp
|
||||
sed -e "s|Firmware updated on [0-9/]*.|Firmware updated on $(TODAY).|g" files.tmp > ../../www/files.html
|
||||
rm files.tmp
|
||||
136
boot_logo.c
Normal file
136
boot_logo.c
Normal file
@@ -0,0 +1,136 @@
|
||||
/* boot_logo.c */
|
||||
/* 2012, rok.krajnc@gmail.com */
|
||||
|
||||
#include "fpga.h"
|
||||
#include "fat.h"
|
||||
#include "boot_print.h"
|
||||
|
||||
static const unsigned int logo_width = 29;
|
||||
static const unsigned int logo_height = 80;
|
||||
|
||||
static const char boot_logo[80][29] = {
|
||||
{ 0x00, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0xff, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xfc, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0xff, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xfc, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x01, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x0f, 0xf0, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x01, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x0f, 0xf0, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x01, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x20, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x01, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x20, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x80, 0x03, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x1f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x80, 0x03, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x1f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xfe, 0x03, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0xff, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xfe, 0x03, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0xff, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xff, 0xf7, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xff, 0xf7, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xff, 0xf0, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xff, 0xf0, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xff, 0xf0, 0x03, 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xff, 0xf0, 0x03, 0xff, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xff, 0xe0, 0x00, 0x1f, 0x80, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xff, 0xe0, 0x00, 0x1f, 0x80, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xff, 0xc0, 0x00, 0x01, 0xc0, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xff, 0xc0, 0x00, 0x01, 0xc0, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xff, 0xc0, 0x00, 0x07, 0xff, 0x80, 0x0f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xff, 0xc0, 0x00, 0x07, 0xff, 0x80, 0x0f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xff, 0x80, 0x00, 0x1f, 0xff, 0xfc, 0x7f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0x81, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00 },
|
||||
{ 0xff, 0x80, 0x00, 0x1f, 0xff, 0xfc, 0x7f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0x81, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x7f, 0xff, 0xe0, 0x00 },
|
||||
{ 0x0f, 0x80, 0x00, 0x7f, 0xff, 0xfe, 0x1f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xe0, 0x00, 0x01, 0xff, 0xff, 0x81, 0xff, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x80 },
|
||||
{ 0x0f, 0x80, 0x00, 0x7f, 0xff, 0xfe, 0x1f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xe0, 0x00, 0x01, 0xff, 0xff, 0x81, 0xff, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x80 },
|
||||
{ 0x40, 0xe0, 0x01, 0xff, 0xff, 0xe0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xe0, 0x00, 0x07, 0xff, 0xe0, 0x00, 0x0f, 0xfc, 0x00, 0x01, 0xff, 0xe0, 0x00, 0x7f, 0x00 },
|
||||
{ 0x40, 0xe0, 0x01, 0xff, 0xff, 0xe0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xe0, 0x00, 0x07, 0xff, 0xe0, 0x00, 0x0f, 0xfc, 0x00, 0x01, 0xff, 0xe0, 0x00, 0x7f, 0x00 },
|
||||
{ 0x00, 0xfc, 0x07, 0xff, 0xfe, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf0, 0x00, 0x0f, 0xff, 0xe0, 0x00, 0x0f, 0xf8, 0x00, 0x07, 0xff, 0x00, 0x00, 0x0f, 0x00 },
|
||||
{ 0x00, 0xfc, 0x07, 0xff, 0xfe, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf0, 0x00, 0x0f, 0xff, 0xe0, 0x00, 0x0f, 0xf8, 0x00, 0x07, 0xff, 0x00, 0x00, 0x0f, 0x00 },
|
||||
{ 0x00, 0x3f, 0x8f, 0xff, 0xc0, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xc0, 0x00, 0x1f, 0xf8, 0x00, 0x1f, 0xfc, 0x00, 0x00, 0x0f, 0x00 },
|
||||
{ 0x00, 0x3f, 0x8f, 0xff, 0xc0, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xc0, 0x00, 0x1f, 0xf8, 0x00, 0x1f, 0xfc, 0x00, 0x00, 0x0f, 0x00 },
|
||||
{ 0x00, 0x00, 0xff, 0xf8, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcf, 0xf8, 0x00, 0x3e, 0xff, 0xc0, 0x00, 0x1f, 0xf8, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x0e, 0x00 },
|
||||
{ 0x00, 0x00, 0xff, 0xf8, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcf, 0xf8, 0x00, 0x3e, 0xff, 0xc0, 0x00, 0x1f, 0xf8, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x0e, 0x00 },
|
||||
{ 0x00, 0x00, 0x03, 0xc7, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcf, 0xf8, 0x00, 0x7c, 0xff, 0xc0, 0x00, 0x3f, 0xf0, 0x00, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x03, 0xc7, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcf, 0xf8, 0x00, 0x7c, 0xff, 0xc0, 0x00, 0x3f, 0xf0, 0x00, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc7, 0xf8, 0x00, 0xf9, 0xff, 0x80, 0x00, 0x3f, 0xf0, 0x01, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc7, 0xf8, 0x00, 0xf9, 0xff, 0x80, 0x00, 0x3f, 0xf0, 0x01, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x07, 0x87, 0xfc, 0x01, 0xf1, 0xff, 0x80, 0x00, 0x3f, 0xf0, 0x03, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x07, 0x87, 0xfc, 0x01, 0xf1, 0xff, 0x80, 0x00, 0x3f, 0xf0, 0x03, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x07, 0x87, 0xfc, 0x03, 0xe1, 0xff, 0x00, 0x00, 0x7f, 0xe0, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x07, 0x87, 0xfc, 0x03, 0xe1, 0xff, 0x00, 0x00, 0x7f, 0xe0, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x83, 0xfc, 0x07, 0x83, 0xff, 0x00, 0x00, 0x7f, 0xe0, 0x07, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x83, 0xfc, 0x07, 0x83, 0xff, 0x00, 0x00, 0x7f, 0xe0, 0x07, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x03, 0xfe, 0x0f, 0x03, 0xff, 0x00, 0x00, 0x7f, 0xc0, 0x07, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x03, 0xfe, 0x0f, 0x03, 0xff, 0x00, 0x00, 0x7f, 0xc0, 0x07, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x1f, 0x87, 0xc0, 0xfc, 0x0f, 0xe0, 0x7c, 0x3f, 0x01, 0xfc, 0x00, 0x0f, 0x03, 0xfe, 0x1e, 0x03, 0xfe, 0x00, 0x00, 0xff, 0xc0, 0x07, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x1f, 0x87, 0xc0, 0xfc, 0x0f, 0xe0, 0x7c, 0x3f, 0x01, 0xfc, 0x00, 0x0f, 0x03, 0xfe, 0x1e, 0x03, 0xfe, 0x00, 0x00, 0xff, 0xc0, 0x07, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x07, 0xbf, 0xe3, 0xfe, 0x01, 0xe0, 0x1c, 0xff, 0xc0, 0x3c, 0x00, 0x1f, 0x01, 0xff, 0x3c, 0x07, 0xfe, 0x00, 0x00, 0xff, 0xc0, 0x07, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xc0 },
|
||||
{ 0x00, 0x07, 0xbf, 0xe3, 0xfe, 0x01, 0xe0, 0x1c, 0xff, 0xc0, 0x3c, 0x00, 0x1f, 0x01, 0xff, 0x3c, 0x07, 0xfe, 0x00, 0x00, 0xff, 0xc0, 0x07, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xc0 },
|
||||
{ 0x00, 0x07, 0xe0, 0xfc, 0x0e, 0x03, 0xc0, 0x3f, 0x01, 0xc0, 0x38, 0x00, 0x1e, 0x01, 0xff, 0x78, 0x07, 0xfe, 0x00, 0x00, 0xff, 0x80, 0x07, 0xfe, 0x00, 0x00, 0x1f, 0xfc, 0x00 },
|
||||
{ 0x00, 0x07, 0xe0, 0xfc, 0x0e, 0x03, 0xc0, 0x3f, 0x01, 0xc0, 0x38, 0x00, 0x1e, 0x01, 0xff, 0x78, 0x07, 0xfe, 0x00, 0x00, 0xff, 0x80, 0x07, 0xfe, 0x00, 0x00, 0x1f, 0xfc, 0x00 },
|
||||
{ 0x00, 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, 0x3c, 0x01, 0xc0, 0x78, 0x00, 0x1e, 0x00, 0xff, 0xf0, 0x07, 0xfc, 0x00, 0x01, 0xff, 0x80, 0x07, 0xfe, 0x00, 0x00, 0x1f, 0xf8, 0x00 },
|
||||
{ 0x00, 0x07, 0x80, 0xf0, 0x1e, 0x03, 0xc0, 0x3c, 0x01, 0xc0, 0x78, 0x00, 0x1e, 0x00, 0xff, 0xf0, 0x07, 0xfc, 0x00, 0x01, 0xff, 0x80, 0x07, 0xfe, 0x00, 0x00, 0x1f, 0xf8, 0x00 },
|
||||
{ 0x00, 0x0f, 0x00, 0xe0, 0x1e, 0x03, 0xc0, 0x38, 0x03, 0xc0, 0x78, 0x00, 0x3c, 0x00, 0xff, 0xe0, 0x0f, 0xfc, 0x00, 0x01, 0xff, 0x80, 0x07, 0xfe, 0x00, 0x00, 0x1f, 0xf8, 0x00 },
|
||||
{ 0x00, 0x0f, 0x00, 0xe0, 0x1e, 0x03, 0xc0, 0x38, 0x03, 0xc0, 0x78, 0x00, 0x3c, 0x00, 0xff, 0xe0, 0x0f, 0xfc, 0x00, 0x01, 0xff, 0x80, 0x07, 0xfe, 0x00, 0x00, 0x1f, 0xf8, 0x00 },
|
||||
{ 0x00, 0x0e, 0x01, 0xe0, 0x1c, 0x07, 0x80, 0x78, 0x03, 0x80, 0xf0, 0x00, 0x3c, 0x00, 0x7f, 0xc0, 0x0f, 0xfc, 0x00, 0x01, 0xff, 0x00, 0x03, 0xff, 0x00, 0x00, 0x1f, 0xf8, 0x00 },
|
||||
{ 0x00, 0x0e, 0x01, 0xe0, 0x1c, 0x07, 0x80, 0x78, 0x03, 0x80, 0xf0, 0x00, 0x3c, 0x00, 0x7f, 0xc0, 0x0f, 0xfc, 0x00, 0x01, 0xff, 0x00, 0x03, 0xff, 0x00, 0x00, 0x1f, 0xf8, 0x00 },
|
||||
{ 0x00, 0x0e, 0x01, 0xe0, 0x3c, 0x07, 0x80, 0x78, 0x03, 0x80, 0xf0, 0x00, 0x3c, 0x00, 0x7f, 0x80, 0x0f, 0xf8, 0x00, 0x03, 0xff, 0x00, 0x03, 0xff, 0x00, 0x00, 0x3f, 0xf0, 0x00 },
|
||||
{ 0x00, 0x0e, 0x01, 0xe0, 0x3c, 0x07, 0x80, 0x78, 0x03, 0x80, 0xf0, 0x00, 0x3c, 0x00, 0x7f, 0x80, 0x0f, 0xf8, 0x00, 0x03, 0xff, 0x00, 0x03, 0xff, 0x00, 0x00, 0x3f, 0xf0, 0x00 },
|
||||
{ 0x00, 0x1e, 0x01, 0xc0, 0x3c, 0x07, 0x80, 0x70, 0x07, 0x80, 0xf0, 0x00, 0x78, 0x00, 0x7f, 0x00, 0x1f, 0xf8, 0x00, 0x03, 0xff, 0x00, 0x01, 0xff, 0x80, 0x00, 0x3f, 0xf0, 0x00 },
|
||||
{ 0x00, 0x1e, 0x01, 0xc0, 0x3c, 0x07, 0x80, 0x70, 0x07, 0x80, 0xf0, 0x00, 0x78, 0x00, 0x7f, 0x00, 0x1f, 0xf8, 0x00, 0x03, 0xff, 0x00, 0x01, 0xff, 0x80, 0x00, 0x3f, 0xf0, 0x00 },
|
||||
{ 0x00, 0x1e, 0x03, 0xc0, 0x38, 0x0f, 0x00, 0xf0, 0x07, 0x01, 0xe0, 0x00, 0x78, 0x00, 0x3e, 0x00, 0x1f, 0xf8, 0x00, 0x03, 0xfe, 0x00, 0x00, 0x7f, 0xe0, 0x00, 0x7f, 0xf0, 0x00 },
|
||||
{ 0x00, 0x1e, 0x03, 0xc0, 0x38, 0x0f, 0x00, 0xf0, 0x07, 0x01, 0xe0, 0x00, 0x78, 0x00, 0x3e, 0x00, 0x1f, 0xf8, 0x00, 0x03, 0xfe, 0x00, 0x00, 0x7f, 0xe0, 0x00, 0x7f, 0xf0, 0x00 },
|
||||
{ 0x00, 0x1c, 0x03, 0x80, 0x78, 0x0f, 0x00, 0xe0, 0x0f, 0x01, 0xe0, 0x07, 0xff, 0x00, 0x3c, 0x01, 0xff, 0xff, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xe0, 0x00 },
|
||||
{ 0x00, 0x1c, 0x03, 0x80, 0x78, 0x0f, 0x00, 0xe0, 0x0f, 0x01, 0xe0, 0x07, 0xff, 0x00, 0x3c, 0x01, 0xff, 0xff, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xe0, 0x00 },
|
||||
{ 0x00, 0x3c, 0x03, 0x80, 0x7f, 0x0f, 0xe0, 0xe0, 0x0f, 0xc1, 0xfc, 0x1f, 0xff, 0xc0, 0x38, 0x0f, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xf0, 0x00, 0x01, 0xff, 0xff, 0xfc, 0x00, 0x00 },
|
||||
{ 0x00, 0x3c, 0x03, 0x80, 0x7f, 0x0f, 0xe0, 0xe0, 0x0f, 0xc1, 0xfc, 0x1f, 0xff, 0xc0, 0x38, 0x0f, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xf0, 0x00, 0x01, 0xff, 0xff, 0xfc, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
|
||||
};
|
||||
|
||||
void draw_boot_logo()
|
||||
{
|
||||
unsigned int line;
|
||||
unsigned short int offset = 0;
|
||||
char * p;
|
||||
fileTYPE file;
|
||||
|
||||
// check if there's a logo file on disk
|
||||
if(FileOpen(&file,"LOGO RAW")) {
|
||||
if(file.size == logo_width * logo_height) {
|
||||
char buffer[512+logo_width];
|
||||
int fill = 0, cnt = logo_width * logo_height, i;
|
||||
|
||||
while(cnt) {
|
||||
if(fill < logo_width) {
|
||||
FileRead(&file, buffer+fill);
|
||||
FileNextSector(&file);
|
||||
fill += 512;
|
||||
}
|
||||
|
||||
BootDraw(buffer, logo_width, offset);
|
||||
offset += 640/8;
|
||||
bcury+=640/8;
|
||||
|
||||
// remove line from buffer
|
||||
for(i=0;i<512;i++)
|
||||
buffer[i] = buffer[i+logo_width];
|
||||
|
||||
cnt -= logo_width;
|
||||
fill -= logo_width;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (line=0; line<logo_height; line++) {
|
||||
p = (char*)boot_logo[line];
|
||||
BootDraw(p, logo_width, offset);
|
||||
offset += 640/8;
|
||||
bcury+=640/8;
|
||||
}
|
||||
}
|
||||
|
||||
11
boot_logo.h
Normal file
11
boot_logo.h
Normal file
@@ -0,0 +1,11 @@
|
||||
/* boot_logo.h */
|
||||
/* 2012, rok.krajnc@gmail.com */
|
||||
|
||||
#ifndef __BOOT_LOGO_H__
|
||||
#define __BOOT_LOGO_H__
|
||||
|
||||
|
||||
void draw_boot_logo();
|
||||
|
||||
|
||||
#endif // __BOOT_LOGO_H__
|
||||
127
boot_print.c
Normal file
127
boot_print.c
Normal file
@@ -0,0 +1,127 @@
|
||||
/* boot_print.c */
|
||||
/* 2012, rok.krajnc@gmail.com */
|
||||
|
||||
#include "fpga.h"
|
||||
#include "string.h"
|
||||
|
||||
|
||||
unsigned short bcurx;
|
||||
unsigned short bcury;
|
||||
|
||||
static const char boot_font [96][8] = {
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // SPACE
|
||||
{0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x00}, // !
|
||||
{0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // "
|
||||
{0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00}, // #
|
||||
{0x18, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x18, 0x00}, // $
|
||||
{0x00, 0x66, 0xAC, 0xD8, 0x36, 0x6A, 0xCC, 0x00}, // %
|
||||
{0x38, 0x6C, 0x68, 0x76, 0xDC, 0xCE, 0x7B, 0x00}, // &
|
||||
{0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00}, // '
|
||||
{0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00}, // (
|
||||
{0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00}, // )
|
||||
{0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // *
|
||||
{0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00}, // +
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30}, // ,
|
||||
{0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00}, // -
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00}, // .
|
||||
{0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x00}, // /
|
||||
{0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x3C, 0x00}, // 0
|
||||
{0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x00}, // 1
|
||||
{0x3C, 0x66, 0x06, 0x0C, 0x18, 0x30, 0x7E, 0x00}, // 2
|
||||
{0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00}, // 3
|
||||
{0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x0C, 0x00}, // 4
|
||||
{0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0x00}, // 5
|
||||
{0x1C, 0x30, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00}, // 6
|
||||
{0x7E, 0x06, 0x06, 0x0C, 0x18, 0x18, 0x18, 0x00}, // 7
|
||||
{0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00}, // 8
|
||||
{0x3C, 0x66, 0x66, 0x3E, 0x06, 0x0C, 0x38, 0x00}, // 9
|
||||
{0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00}, // :
|
||||
{0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30}, // ;
|
||||
{0x00, 0x06, 0x18, 0x60, 0x18, 0x06, 0x00, 0x00}, // <
|
||||
{0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00}, // =
|
||||
{0x00, 0x60, 0x18, 0x06, 0x18, 0x60, 0x00, 0x00}, // >
|
||||
{0x3C, 0x66, 0x06, 0x0C, 0x18, 0x00, 0x18, 0x00}, // ?
|
||||
{0x7C, 0xC6, 0xDE, 0xD6, 0xDE, 0xC0, 0x78, 0x00}, // @
|
||||
{0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00}, // A
|
||||
{0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00}, // B
|
||||
{0x1E, 0x30, 0x60, 0x60, 0x60, 0x30, 0x1E, 0x00}, // C
|
||||
{0x78, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0x78, 0x00}, // D
|
||||
{0x7E, 0x60, 0x60, 0x78, 0x60, 0x60, 0x7E, 0x00}, // E
|
||||
{0x7E, 0x60, 0x60, 0x78, 0x60, 0x60, 0x60, 0x00}, // F
|
||||
{0x3C, 0x66, 0x60, 0x6E, 0x66, 0x66, 0x3E, 0x00}, // G
|
||||
{0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00}, // H
|
||||
{0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00}, // I
|
||||
{0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x3C, 0x00}, // J
|
||||
{0xC6, 0xCC, 0xD8, 0xF0, 0xD8, 0xCC, 0xC6, 0x00}, // K
|
||||
{0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00}, // L
|
||||
{0xC6, 0xEE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0x00}, // M
|
||||
{0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00}, // N
|
||||
{0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00}, // O
|
||||
{0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x00}, // P
|
||||
{0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xDC, 0x7E, 0x00}, // Q
|
||||
{0x7C, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x00}, // R
|
||||
{0x3C, 0x66, 0x70, 0x3C, 0x0E, 0x66, 0x3C, 0x00}, // S
|
||||
{0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00}, // T
|
||||
{0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00}, // U
|
||||
{0x66, 0x66, 0x66, 0x66, 0x3C, 0x3C, 0x18, 0x00}, // V
|
||||
{0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00}, // W
|
||||
{0xC3, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0xC3, 0x00}, // X
|
||||
{0xC3, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x00}, // Y
|
||||
{0xFE, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xFE, 0x00}, // Z
|
||||
{0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00}, // [
|
||||
{0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x00}, // Backslash
|
||||
{0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00}, // ]
|
||||
{0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00}, // ^
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE}, // _
|
||||
{0x18, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00}, // `
|
||||
{0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00}, // a
|
||||
{0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x00}, // b
|
||||
{0x00, 0x00, 0x3C, 0x60, 0x60, 0x60, 0x3C, 0x00}, // c
|
||||
{0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00}, // d
|
||||
{0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00}, // e
|
||||
{0x1C, 0x30, 0x7C, 0x30, 0x30, 0x30, 0x30, 0x00}, // f
|
||||
{0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x3C}, // g
|
||||
{0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00}, // h
|
||||
{0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x0C, 0x00}, // i
|
||||
{0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x78}, // j
|
||||
{0x60, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00}, // k
|
||||
{0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0C, 0x00}, // l
|
||||
{0x00, 0x00, 0xEC, 0xFE, 0xD6, 0xC6, 0xC6, 0x00}, // m
|
||||
{0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00}, // n
|
||||
{0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00}, // o
|
||||
{0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60}, // p
|
||||
{0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x06}, // q
|
||||
{0x00, 0x00, 0x7C, 0x66, 0x60, 0x60, 0x60, 0x00}, // r
|
||||
{0x00, 0x00, 0x3C, 0x60, 0x3C, 0x06, 0x7C, 0x00}, // s
|
||||
{0x30, 0x30, 0x7C, 0x30, 0x30, 0x30, 0x1C, 0x00}, // t
|
||||
{0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00}, // u
|
||||
{0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00}, // v
|
||||
{0x00, 0x00, 0xC6, 0xC6, 0xD6, 0xFE, 0x6C, 0x00}, // w
|
||||
{0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00}, // x
|
||||
{0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x30}, // y
|
||||
{0x00, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00}, // z
|
||||
{0x0E, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0E, 0x00}, // {
|
||||
{0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00}, // |
|
||||
{0x70, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x70, 0x00}, // }
|
||||
{0x72, 0x9C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // ~
|
||||
{0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0x00} //
|
||||
};
|
||||
|
||||
|
||||
void BootPrintEx(char * str)
|
||||
{
|
||||
char buf[80];
|
||||
unsigned char i,j;
|
||||
unsigned char len;
|
||||
|
||||
len = strlen(str);
|
||||
len = (len>80) ? 80 : len;
|
||||
|
||||
for(j=0; j<8; j++) {
|
||||
for(i=0; i<len; i++) {
|
||||
buf[i] = boot_font[str[i]-32][j];
|
||||
}
|
||||
BootDraw(buf, len, bcury+=640/8);
|
||||
}
|
||||
}
|
||||
|
||||
15
boot_print.h
Normal file
15
boot_print.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/* boot_print.h */
|
||||
/* 2012, rok.krajnc@gmail.com */
|
||||
|
||||
#ifndef __BOOT_PRINT_H__
|
||||
#define __BOOT_PRINT_H__
|
||||
|
||||
|
||||
extern unsigned short bcurx;
|
||||
extern unsigned short bcury;
|
||||
|
||||
void BootPrintEx(char * str);
|
||||
|
||||
|
||||
#endif // __BOOT_PRINT_H__
|
||||
|
||||
290
charrom.h
Normal file
290
charrom.h
Normal file
@@ -0,0 +1,290 @@
|
||||
#ifndef CHARROM_H
|
||||
#define CHARROM_H
|
||||
|
||||
/*
|
||||
Write protect. Characters are defined in columns, not rows, LSB first
|
||||
. . . . . . . .
|
||||
. . * * * . . .
|
||||
. * . . . * . .
|
||||
. * . . . * . .
|
||||
* * * * * * * .
|
||||
* * * * * * * .
|
||||
* * * * * * * .
|
||||
. . . . . . . .
|
||||
0x70,0x7c,0x72,0x72,0x72,0x7c,0x70,0x00,0x00
|
||||
|
||||
Write enable
|
||||
. . . . . . . .
|
||||
. . . . . * * .
|
||||
. . . . * . . *
|
||||
. . . . * . . *
|
||||
* * * * * * . .
|
||||
* * * * * * . .
|
||||
* * * * * * . .
|
||||
. . . . . . . .
|
||||
0x70,0x70,0x70,0x70,0x7c,0x72,0x02,0x0c
|
||||
|
||||
*/
|
||||
|
||||
// *character font
|
||||
unsigned char charfont[256][8] =
|
||||
{
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0 [0x0]
|
||||
{0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55}, // 1 [0x1]
|
||||
{0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A}, // 2 [0x2]
|
||||
{0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14}, // 3 [0x3]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 4 [0x4]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 5 [0x5]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 6 [0x6]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 7 [0x7]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 8 [0x8]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 9 [0x9]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 10 [0xa]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 11 [0xb]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 12 [0xc]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 13 [0xd]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 14 [0xe]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 15 [0xf]
|
||||
{0x08,0x08,0x1C,0x1C,0x3E,0x3E,0x7F,0x7F}, // 16 [0x10] arrow left
|
||||
{0x7F,0x7F,0x3E,0x3E,0x1C,0x1C,0x08,0x08}, // 17 [0x11] arrow right
|
||||
{0x00,0x10,0x18,0x7c,0x7c,0x18,0x10,0x00}, // 18 [0x12] arrow up
|
||||
{0x00,0x10,0x30,0x7c,0x7c,0x30,0x10,0x00}, // 19 [0x13] arrow down
|
||||
{0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x00,0x00}, // 20 [0x14]
|
||||
{0x00,0x00,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C}, // 21 [0x15]
|
||||
{0x00,0x7C,0x7C,0x38,0x38,0x10,0x10,0x00}, // 22 [0x16] mini arrow right
|
||||
{0x70,0x7c,0x72,0x72,0x72,0x7c,0x70,0x00}, // 23 [0x17] write protect
|
||||
{0x70,0x70,0x70,0x70,0x7c,0x72,0x02,0x0c}, // 24 [0x18] write enable
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 25 [0x19]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 26 [0x1a]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 27 [0x1b]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 28 [0x1c]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 29 [0x1d]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 30 [0x1e]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 31 [0x1f]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 32 [0x20]
|
||||
{0x00,0x00,0x00,0x5F,0x5F,0x00,0x00,0x00}, // 33 [0x21]
|
||||
{0x00,0x03,0x03,0x00,0x03,0x03,0x00,0x00}, // 34 [0x22]
|
||||
{0x14,0x7F,0x7F,0x14,0x7F,0x7F,0x14,0x00}, // 35 [0x23]
|
||||
{0x00,0x24,0x2E,0x6B,0x6B,0x3A,0x12,0x00}, // 36 [0x24]
|
||||
{0x4C,0x6A,0x36,0x18,0x6C,0x56,0x32,0x00}, // 37 [0x25]
|
||||
{0x30,0x7E,0x4F,0x59,0x77,0x3A,0x68,0x40}, // 38 [0x26]
|
||||
{0x00,0x00,0x04,0x07,0x03,0x00,0x00,0x00}, // 39 [0x27]
|
||||
{0x00,0x00,0x1C,0x3E,0x63,0x41,0x00,0x00}, // 40 [0x28]
|
||||
{0x00,0x00,0x41,0x63,0x3E,0x1C,0x00,0x00}, // 41 [0x29]
|
||||
{0x08,0x2A,0x3E,0x1C,0x1C,0x3E,0x2A,0x08}, // 42 [0x2a]
|
||||
{0x00,0x08,0x08,0x3E,0x3E,0x08,0x08,0x00}, // 43 [0x2b]
|
||||
{0x00,0x00,0x80,0xE0,0x60,0x00,0x00,0x00}, // 44 [0x2c]
|
||||
{0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00}, // 45 [0x2d]
|
||||
{0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00}, // 46 [0x2e]
|
||||
{0x40,0x60,0x30,0x18,0x0C,0x06,0x03,0x01}, // 47 [0x2f]
|
||||
{0x00,0x3E,0x7F,0x59,0x4D,0x7F,0x3E,0x00}, // 48 [0x30]
|
||||
{0x00,0x04,0x06,0x7F,0x7F,0x00,0x00,0x00}, // 49 [0x31]
|
||||
{0x00,0x42,0x63,0x71,0x59,0x4F,0x46,0x00}, // 50 [0x32]
|
||||
{0x00,0x22,0x63,0x49,0x49,0x7F,0x36,0x00}, // 51 [0x33]
|
||||
{0x18,0x1C,0x16,0x13,0x7F,0x7F,0x10,0x00}, // 52 [0x34]
|
||||
{0x00,0x27,0x67,0x45,0x45,0x7D,0x39,0x00}, // 53 [0x35]
|
||||
{0x00,0x3C,0x7E,0x4B,0x49,0x79,0x30,0x00}, // 54 [0x36]
|
||||
{0x00,0x01,0x01,0x71,0x79,0x0F,0x07,0x00}, // 55 [0x37]
|
||||
{0x00,0x36,0x7F,0x49,0x49,0x7F,0x36,0x00}, // 56 [0x38]
|
||||
{0x00,0x06,0x4F,0x49,0x69,0x3F,0x1E,0x00}, // 57 [0x39]
|
||||
{0x00,0x00,0x00,0x66,0x66,0x00,0x00,0x00}, // 58 [0x3a]
|
||||
{0x00,0x00,0x80,0xE6,0x66,0x00,0x00,0x00}, // 59 [0x3b]
|
||||
{0x00,0x08,0x08,0x14,0x14,0x22,0x22,0x00}, // 60 [0x3c]
|
||||
{0x00,0x14,0x14,0x14,0x14,0x14,0x14,0x00}, // 61 [0x3d]
|
||||
{0x00,0x22,0x22,0x14,0x14,0x08,0x08,0x00}, // 62 [0x3e]
|
||||
{0x00,0x02,0x03,0x51,0x59,0x0F,0x06,0x00}, // 63 [0x3f]
|
||||
{0x3E,0x7F,0x41,0x5D,0x55,0x1F,0x1E,0x00}, // 64 [0x40]
|
||||
{0x00,0x7E,0x7F,0x09,0x09,0x7F,0x7E,0x00}, // 65 [0x41]
|
||||
{0x00,0x7F,0x7F,0x49,0x49,0x7F,0x36,0x00}, // 66 [0x42]
|
||||
{0x00,0x1C,0x3E,0x63,0x41,0x41,0x41,0x00}, // 67 [0x43]
|
||||
{0x00,0x7F,0x7F,0x41,0x63,0x3E,0x1C,0x00}, // 68 [0x44]
|
||||
{0x00,0x7F,0x7F,0x49,0x49,0x41,0x41,0x00}, // 69 [0x45]
|
||||
{0x00,0x7F,0x7F,0x09,0x09,0x01,0x01,0x00}, // 70 [0x46]
|
||||
{0x00,0x3E,0x7F,0x41,0x49,0x7B,0x7A,0x00}, // 71 [0x47]
|
||||
{0x00,0x7F,0x7F,0x08,0x08,0x7F,0x7F,0x00}, // 72 [0x48]
|
||||
{0x00,0x00,0x41,0x7F,0x7F,0x41,0x00,0x00}, // 73 [0x49]
|
||||
{0x00,0x20,0x60,0x40,0x40,0x7F,0x3F,0x00}, // 74 [0x4a]
|
||||
{0x7F,0x7F,0x08,0x1C,0x36,0x63,0x41,0x00}, // 75 [0x4b]
|
||||
{0x00,0x7F,0x7F,0x40,0x40,0x40,0x40,0x00}, // 76 [0x4c]
|
||||
{0x7F,0x7F,0x06,0x0C,0x06,0x7F,0x7F,0x00}, // 77 [0x4d]
|
||||
{0x7F,0x7F,0x06,0x0C,0x18,0x7F,0x7F,0x00}, // 78 [0x4e]
|
||||
{0x00,0x3E,0x7F,0x41,0x41,0x7F,0x3E,0x00}, // 79 [0x4f]
|
||||
{0x00,0x7F,0x7F,0x09,0x09,0x0F,0x06,0x00}, // 80 [0x50]
|
||||
{0x3E,0x7F,0x41,0x61,0x7F,0x7E,0x40,0x00}, // 81 [0x51]
|
||||
{0x00,0x7F,0x7F,0x09,0x19,0x7F,0x66,0x00}, // 82 [0x52]
|
||||
{0x00,0x26,0x6F,0x4D,0x59,0x7B,0x32,0x00}, // 83 [0x53]
|
||||
{0x00,0x01,0x01,0x7F,0x7F,0x01,0x01,0x00}, // 84 [0x54]
|
||||
{0x00,0x3F,0x7F,0x40,0x40,0x7F,0x3F,0x00}, // 85 [0x55]
|
||||
{0x00,0x0F,0x3F,0x70,0x70,0x3F,0x0F,0x00}, // 86 [0x56]
|
||||
{0x7F,0x7F,0x30,0x18,0x30,0x7F,0x7F,0x00}, // 87 [0x57]
|
||||
{0x41,0x63,0x36,0x1C,0x1C,0x36,0x63,0x41}, // 88 [0x58]
|
||||
{0x01,0x03,0x06,0x7C,0x7C,0x06,0x03,0x01}, // 89 [0x59]
|
||||
{0x61,0x71,0x59,0x4D,0x47,0x43,0x41,0x00}, // 90 [0x5a]
|
||||
{0x00,0x00,0x7F,0x7F,0x41,0x41,0x00,0x00}, // 91 [0x5b]
|
||||
{0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0x40}, // 92 [0x5c]
|
||||
{0x00,0x00,0x41,0x41,0x7F,0x7F,0x00,0x00}, // 93 [0x5d]
|
||||
{0x08,0x0C,0x06,0x03,0x06,0x0C,0x08,0x00}, // 94 [0x5e]
|
||||
{0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00}, // 95 [0x5f]
|
||||
{0x00,0x00,0x00,0x03,0x07,0x04,0x00,0x00}, // 96 [0x60]
|
||||
{0x00,0x20,0x74,0x54,0x54,0x7C,0x78,0x00}, // 97 [0x61]
|
||||
{0x00,0x7F,0x7F,0x44,0x44,0x7C,0x38,0x00}, // 98 [0x62]
|
||||
{0x00,0x38,0x7C,0x44,0x44,0x44,0x00,0x00}, // 99 [0x63]
|
||||
{0x00,0x38,0x7C,0x44,0x44,0x7F,0x7F,0x00}, // 100 [0x64]
|
||||
{0x00,0x38,0x7C,0x54,0x54,0x5C,0x18,0x00}, // 101 [0x65]
|
||||
{0x00,0x04,0x7E,0x7F,0x05,0x05,0x00,0x00}, // 102 [0x66]
|
||||
{0x00,0x18,0xBC,0xA4,0xA4,0xFC,0x7C,0x00}, // 103 [0x67]
|
||||
{0x00,0x7F,0x7F,0x04,0x04,0x7C,0x78,0x00}, // 104 [0x68]
|
||||
{0x00,0x00,0x00,0x3D,0x7D,0x40,0x00,0x00}, // 105 [0x69]
|
||||
{0x00,0x80,0x80,0x80,0xFD,0x7D,0x00,0x00}, // 106 [0x6a]
|
||||
{0x00,0x7F,0x7F,0x10,0x38,0x6C,0x44,0x00}, // 107 [0x6b]
|
||||
{0x00,0x00,0x00,0x3F,0x7F,0x40,0x00,0x00}, // 108 [0x6c]
|
||||
{0x7C,0x7C,0x0C,0x18,0x0C,0x7C,0x78,0x00}, // 109 [0x6d]
|
||||
{0x00,0x7C,0x7C,0x04,0x04,0x7C,0x78,0x00}, // 110 [0x6e]
|
||||
{0x00,0x38,0x7C,0x44,0x44,0x7C,0x38,0x00}, // 111 [0x6f]
|
||||
{0x00,0xFC,0xFC,0x24,0x24,0x3C,0x18,0x00}, // 112 [0x70]
|
||||
{0x00,0x18,0x3C,0x24,0x24,0xFC,0xFC,0x00}, // 113 [0x71]
|
||||
{0x00,0x7C,0x7C,0x04,0x04,0x0C,0x08,0x00}, // 114 [0x72]
|
||||
{0x00,0x48,0x5C,0x54,0x54,0x74,0x20,0x00}, // 115 [0x73]
|
||||
{0x00,0x04,0x3F,0x7F,0x44,0x44,0x00,0x00}, // 116 [0x74]
|
||||
{0x00,0x3C,0x7C,0x40,0x40,0x7C,0x7C,0x00}, // 117 [0x75]
|
||||
{0x00,0x1C,0x3C,0x60,0x60,0x3C,0x1C,0x00}, // 118 [0x76]
|
||||
{0x3C,0x7C,0x60,0x30,0x60,0x7C,0x3C,0x00}, // 119 [0x77]
|
||||
{0x44,0x6C,0x38,0x10,0x38,0x6C,0x44,0x00}, // 120 [0x78]
|
||||
{0x00,0x1C,0xBC,0xE0,0x60,0x3C,0x1C,0x00}, // 121 [0x79]
|
||||
{0x00,0x44,0x64,0x74,0x5C,0x4C,0x44,0x00}, // 122 [0x7a]
|
||||
{0x00,0x08,0x08,0x3E,0x77,0x41,0x41,0x00}, // 123 [0x7b]
|
||||
{0x00,0x00,0x00,0x7F,0x7F,0x00,0x00,0x00}, // 124 [0x7c]
|
||||
{0x00,0x41,0x41,0x77,0x3E,0x08,0x08,0x00}, // 125 [0x7d]
|
||||
{0x02,0x01,0x01,0x03,0x02,0x02,0x01,0x00}, // 126 [0x7e]
|
||||
{0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x00}, // 127 [0x7f]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 128 [0x80]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 129 [0x81]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 130 [0x82]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 131 [0x83]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 132 [0x84]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 133 [0x85]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 134 [0x86]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 135 [0x87]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 136 [0x88]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 137 [0x89]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 138 [0x8a]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 139 [0x8b]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 140 [0x8c]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 141 [0x8d]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 142 [0x8e]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 143 [0x8f]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 144 [0x90]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 145 [0x91]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 146 [0x92]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 147 [0x93]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 148 [0x94]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 149 [0x95]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 150 [0x96]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 151 [0x97]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 152 [0x98]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 153 [0x99]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 154 [0x9a]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 155 [0x9b]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 156 [0x9c]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 157 [0x9d]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 158 [0x9e]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 159 [0x9f]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 160 [0xa0]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 161 [0xa1]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 162 [0xa2]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 163 [0xa3]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 164 [0xa4]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 165 [0xa5]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 166 [0xa6]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 167 [0xa7]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 168 [0xa8]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 169 [0xa9]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 170 [0xaa]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 171 [0xab]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 172 [0xac]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 173 [0xad]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 174 [0xae]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 175 [0xaf]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 176 [0xb0]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 177 [0xb1]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 178 [0xb2]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 179 [0xb3]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 180 [0xb4]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 181 [0xb5]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 182 [0xb6]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 183 [0xb7]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 184 [0xb8]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 185 [0xb9]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 186 [0xba]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 187 [0xbb]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 188 [0xbc]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 189 [0xbd]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 190 [0xbe]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 191 [0xbf]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 192 [0xc0]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 193 [0xc1]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 194 [0xc2]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 195 [0xc3]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 196 [0xc4]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 197 [0xc5]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 198 [0xc6]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 199 [0xc7]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 200 [0xc8]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 201 [0xc9]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 202 [0xca]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 203 [0xcb]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 204 [0xcc]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 205 [0xcd]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 206 [0xce]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 207 [0xcf]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 208 [0xd0]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 209 [0xd1]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 210 [0xd2]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 211 [0xd3]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 212 [0xd4]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 213 [0xd5]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 214 [0xd6]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 215 [0xd7]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 216 [0xd8]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 217 [0xd9]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 218 [0xda]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 219 [0xdb]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 220 [0xdc]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 221 [0xdd]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 222 [0xde]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 223 [0xdf]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 224 [0xe0]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 225 [0xe1]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 226 [0xe2]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 227 [0xe3]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 228 [0xe4]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 229 [0xe5]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 230 [0xe6]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 231 [0xe7]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 232 [0xe8]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 233 [0xe9]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 234 [0xea]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 235 [0xeb]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 236 [0xec]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 237 [0xed]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 238 [0xee]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 239 [0xef]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 240 [0xf0]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 241 [0xf1]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 242 [0xf2]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 243 [0xf3]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 244 [0xf4]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 245 [0xf5]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 246 [0xf6]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 247 [0xf7]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 248 [0xf8]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 249 [0xf9]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 250 [0xfa]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 251 [0xfb]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 252 [0xfc]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 253 [0xfd]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 254 [0xfe]
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // 255 [0xff]
|
||||
};
|
||||
|
||||
#endif
|
||||
420
config.c
Normal file
420
config.c
Normal file
@@ -0,0 +1,420 @@
|
||||
#include "errors.h"
|
||||
#include "hardware.h"
|
||||
#include "mmc.h"
|
||||
#include "fat.h"
|
||||
#include "osd.h"
|
||||
#include "fpga.h"
|
||||
#include "fdd.h"
|
||||
#include "hdd.h"
|
||||
#include "firmware.h"
|
||||
#include "menu.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
configTYPE config;
|
||||
fileTYPE file;
|
||||
extern char s[40];
|
||||
char configfilename[12];
|
||||
char DebugMode=0;
|
||||
|
||||
unsigned char romkey[3072];
|
||||
|
||||
RAFile romfile;
|
||||
|
||||
char UploadKickstart(char *name)
|
||||
{
|
||||
int keysize=0;
|
||||
char filename[12];
|
||||
strncpy(filename, name, 8); // copy base name
|
||||
strcpy(&filename[8], "ROM"); // add extension
|
||||
|
||||
BootPrint("Checking for Amiga Forever key file:");
|
||||
if(FileOpen(&file,"ROM KEY"))
|
||||
{
|
||||
keysize=file.size;
|
||||
if(file.size<sizeof(romkey))
|
||||
{
|
||||
int c=0;
|
||||
while(c<keysize)
|
||||
{
|
||||
FileRead(&file, &romkey[c]);
|
||||
c+=512;
|
||||
FileNextSector(&file);
|
||||
}
|
||||
BootPrint("Loaded Amiga Forever key file");
|
||||
}
|
||||
else
|
||||
BootPrint("Amiga Forever keyfile is too large!");
|
||||
}
|
||||
|
||||
BootPrint("Loading file: ");
|
||||
BootPrint(filename);
|
||||
|
||||
if (RAOpen(&romfile, filename))
|
||||
{
|
||||
if (romfile.size == 0x80000)
|
||||
{ // 512KB Kickstart ROM
|
||||
BootPrint("Uploading 512 KB Kickstart...");
|
||||
PrepareBootUpload(0xF8, 0x08);
|
||||
SendFile(&romfile);
|
||||
return(1);
|
||||
}
|
||||
if ((romfile.size == 0x8000b) && keysize)
|
||||
{ // 512KB Kickstart ROM
|
||||
BootPrint("Uploading 512 KB Kickstart (Probably Amiga Forever encrypted...)");
|
||||
PrepareBootUpload(0xF8, 0x08);
|
||||
SendFileEncrypted(&romfile,romkey,keysize);
|
||||
return(1);
|
||||
}
|
||||
else if (romfile.size == 0x40000)
|
||||
{ // 256KB Kickstart ROM
|
||||
BootPrint("Uploading 256 KB Kickstart...");
|
||||
PrepareBootUpload(0xF8, 0x04);
|
||||
SendFile(&romfile);
|
||||
return(1);
|
||||
}
|
||||
else if ((romfile.size == 0x4000b) && keysize)
|
||||
{ // 256KB Kickstart ROM
|
||||
BootPrint("Uploading 256 KB Kickstart (Probably Amiga Forever encrypted...");
|
||||
PrepareBootUpload(0xF8, 0x04);
|
||||
SendFileEncrypted(&romfile,romkey,keysize);
|
||||
return(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
BootPrint("Unsupported ROM file size!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(s, "No \"%s\" file!", filename);
|
||||
BootPrint(s);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
char UploadActionReplay()
|
||||
{
|
||||
if (RAOpen(&romfile, "AR3 ROM"))
|
||||
{
|
||||
if (romfile.file.size == 0x40000)
|
||||
{ // 256 KB Action Replay 3 ROM
|
||||
BootPrint("\nUploading Action Replay ROM...");
|
||||
PrepareBootUpload(0x40, 0x04);
|
||||
SendFile(&romfile);
|
||||
ClearMemory(0x440000, 0x40000);
|
||||
return(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
BootPrint("\nUnsupported AR3.ROM file size!!!");
|
||||
/* FatalError(6); */
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
void SetConfigurationFilename(int config)
|
||||
{
|
||||
if(config)
|
||||
sprintf(configfilename,"MINIMIG%dCFG",config);
|
||||
else
|
||||
strcpy(configfilename,"MINIMIG CFG");
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned char ConfigurationExists(char *filename)
|
||||
{
|
||||
if(!filename)
|
||||
filename=configfilename; // Use slot-based filename if none provided.
|
||||
if (FileOpen(&file, filename))
|
||||
{
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
unsigned char LoadConfiguration(char *filename)
|
||||
{
|
||||
static const char config_id[] = "MNMGCFG0";
|
||||
char updatekickstart=0;
|
||||
char result=0;
|
||||
unsigned char key;
|
||||
|
||||
if(!filename)
|
||||
filename=configfilename; // Use slot-based filename if none provided.
|
||||
|
||||
// load configuration data
|
||||
if (FileOpen(&file, filename))
|
||||
{
|
||||
BootPrint("Opened configuration file\n");
|
||||
printf("Configuration file size: %lu\r", file.size);
|
||||
if (file.size == sizeof(config))
|
||||
{
|
||||
FileRead(&file, sector_buffer);
|
||||
|
||||
configTYPE *tmpconf=(configTYPE *)§or_buffer;
|
||||
|
||||
// check file id and version
|
||||
if (strncmp(tmpconf->id, config_id, sizeof(config.id)) == 0)
|
||||
{
|
||||
// A few more sanity checks...
|
||||
if(tmpconf->floppy.drives<=4)
|
||||
{
|
||||
// If either the old config and new config have a different kickstart file,
|
||||
// or this is the first boot, we need to upload a kickstart image.
|
||||
if(strncmp(tmpconf->kickstart.name,config.kickstart.name,8)!=0)
|
||||
updatekickstart=true;
|
||||
memcpy((void*)&config, (void*)sector_buffer, sizeof(config));
|
||||
result=1; // We successfully loaded the config.
|
||||
}
|
||||
else
|
||||
BootPrint("Config file sanity check failed!\n");
|
||||
}
|
||||
else
|
||||
BootPrint("Wrong configuration file format!\n");
|
||||
}
|
||||
else
|
||||
printf("Wrong configuration file size: %lu (expected: %lu)\r", file.size, sizeof(config));
|
||||
}
|
||||
if(!result)
|
||||
{
|
||||
BootPrint("Can not open configuration file!\n");
|
||||
|
||||
BootPrint("Setting config defaults\n");
|
||||
|
||||
// set default configuration
|
||||
memset((void*)&config, 0, sizeof(config)); // Finally found default config bug - params were reversed!
|
||||
strncpy(config.id, config_id, sizeof(config.id));
|
||||
strncpy(config.kickstart.name, "KICK ", sizeof(config.kickstart.name));
|
||||
config.kickstart.long_name[0] = 0;
|
||||
config.memory = 0x15;
|
||||
config.cpu = 0;
|
||||
config.chipset = 0;
|
||||
config.floppy.speed=CONFIG_FLOPPY2X;
|
||||
config.floppy.drives=1;
|
||||
config.enable_ide=0;
|
||||
config.hardfile[0].enabled = 1;
|
||||
strncpy(config.hardfile[0].name, "HARDFILE", sizeof(config.hardfile[0].name));
|
||||
config.hardfile[0].long_name[0]=0;
|
||||
strncpy(config.hardfile[1].name, "HARDFILE", sizeof(config.hardfile[1].name));
|
||||
config.hardfile[1].long_name[0]=0;
|
||||
config.hardfile[1].enabled = 2; // Default is access to entire SD card
|
||||
updatekickstart=true;
|
||||
|
||||
BootPrint("Defaults set\n");
|
||||
}
|
||||
|
||||
key = OsdGetCtrl();
|
||||
if (key == KEY_F1)
|
||||
config.chipset |= CONFIG_NTSC; // force NTSC mode if F1 pressed
|
||||
|
||||
if (key == KEY_F2)
|
||||
config.chipset &= ~CONFIG_NTSC; // force PAL mode if F2 pressed
|
||||
|
||||
ApplyConfiguration(updatekickstart);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
void ApplyConfiguration(char reloadkickstart)
|
||||
{
|
||||
ConfigCPU(config.cpu);
|
||||
|
||||
if(reloadkickstart)
|
||||
{
|
||||
ConfigChipset(config.chipset | CONFIG_TURBO); // set CPU in turbo mode
|
||||
ConfigFloppy(1, CONFIG_FLOPPY2X); // set floppy speed
|
||||
OsdReset(RESET_BOOTLOADER);
|
||||
|
||||
if (!UploadKickstart(config.kickstart.name))
|
||||
{
|
||||
strcpy(config.kickstart.name, "KICK ");
|
||||
if (!UploadKickstart(config.kickstart.name))
|
||||
FatalError(6);
|
||||
}
|
||||
|
||||
if (!CheckButton() && !config.disable_ar3) // if menu button pressed don't load Action Replay
|
||||
{
|
||||
#ifndef ACTIONREPLAY_BROKEN
|
||||
if(config.memory & 0x20)
|
||||
BootPrint("More than 2MB of Fast RAM configured - disabling Action Replay!");
|
||||
else
|
||||
UploadActionReplay();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ConfigChipset(config.chipset);
|
||||
ConfigFloppy(config.floppy.drives, config.floppy.speed);
|
||||
}
|
||||
|
||||
// Whether or not we uploaded a kickstart image we now need to set various parameters from the config.
|
||||
|
||||
if(OpenHardfile(0))
|
||||
{
|
||||
switch(hdf[0].type) // Customise message for SD card access
|
||||
{
|
||||
case (HDF_FILE | HDF_SYNTHRDB):
|
||||
sprintf(s, "\nHardfile 1 (with fake RDB): %.8s.%.3s", hdf[1].file.name, &hdf[1].file.name[8]);
|
||||
break;
|
||||
case HDF_FILE:
|
||||
sprintf(s, "\nHardfile 0: %.8s.%.3s", hdf[0].file.name, &hdf[0].file.name[8]);
|
||||
break;
|
||||
case HDF_CARD:
|
||||
sprintf(s, "\nHardfile 0: using entire SD card");
|
||||
break;
|
||||
default:
|
||||
sprintf(s, "\nHardfile 0: using SD card partition %d",hdf[0].type-HDF_CARD); // Number from 1
|
||||
break;
|
||||
}
|
||||
BootPrint(s);
|
||||
sprintf(s, "CHS: %u.%u.%u", hdf[0].cylinders, hdf[0].heads, hdf[0].sectors);
|
||||
BootPrint(s);
|
||||
sprintf(s, "Size: %lu MB", ((((unsigned long) hdf[0].cylinders) * hdf[0].heads * hdf[0].sectors) >> 11));
|
||||
BootPrint(s);
|
||||
sprintf(s, "Offset: %ld", hdf[0].offset);
|
||||
BootPrint(s);
|
||||
}
|
||||
if(OpenHardfile(1))
|
||||
{
|
||||
switch(hdf[1].type)
|
||||
{
|
||||
case (HDF_FILE | HDF_SYNTHRDB):
|
||||
sprintf(s, "\nHardfile 1 (with fake RDB): %.8s.%.3s", hdf[1].file.name, &hdf[1].file.name[8]);
|
||||
break;
|
||||
case HDF_FILE:
|
||||
sprintf(s, "\nHardfile 1: %.8s.%.3s", hdf[1].file.name, &hdf[1].file.name[8]);
|
||||
break;
|
||||
case HDF_CARD:
|
||||
sprintf(s, "\nHardfile 1: using entire SD card");
|
||||
break;
|
||||
default:
|
||||
sprintf(s, "\nHardfile 1: using SD card partition %d",hdf[1].type-HDF_CARD); // Number from 1
|
||||
break;
|
||||
}
|
||||
BootPrint(s);
|
||||
sprintf(s, "CHS: %u.%u.%u", hdf[1].cylinders, hdf[1].heads, hdf[1].sectors);
|
||||
BootPrint(s);
|
||||
sprintf(s, "Size: %lu MB", ((((unsigned long) hdf[1].cylinders) * hdf[1].heads * hdf[1].sectors) >> 11));
|
||||
BootPrint(s);
|
||||
sprintf(s, "Offset: %ld", hdf[1].offset);
|
||||
BootPrint(s);
|
||||
}
|
||||
|
||||
ConfigIDE(config.enable_ide, config.hardfile[0].present && config.hardfile[0].enabled, config.hardfile[1].present && config.hardfile[1].enabled);
|
||||
|
||||
sprintf(s, "CPU clock : %s", config.chipset & 0x01 ? "turbo" : "normal");
|
||||
BootPrint(s);
|
||||
sprintf(s, "Chip RAM size : %s", config_memory_chip_msg[config.memory & 0x03]);
|
||||
BootPrint(s);
|
||||
sprintf(s, "Slow RAM size : %s", config_memory_slow_msg[config.memory >> 2 & 0x03]);
|
||||
BootPrint(s);
|
||||
sprintf(s, "Fast RAM size : %s", config_memory_fast_msg[config.memory >> 4 & 0x03]);
|
||||
BootPrint(s);
|
||||
|
||||
|
||||
sprintf(s, "Floppy drives : %u", config.floppy.drives + 1);
|
||||
BootPrint(s);
|
||||
sprintf(s, "Floppy speed : %s", config.floppy.speed ? "fast": "normal");
|
||||
BootPrint(s);
|
||||
|
||||
BootPrint("");
|
||||
|
||||
sprintf(s, "\nA600 IDE HDC is %s.", config.enable_ide ? "enabled" : "disabled");
|
||||
BootPrint(s);
|
||||
sprintf(s, "Master HDD is %s.", config.hardfile[0].present ? config.hardfile[0].enabled ? "enabled" : "disabled" : "not present");
|
||||
BootPrint(s);
|
||||
sprintf(s, "Slave HDD is %s.", config.hardfile[1].present ? config.hardfile[1].enabled ? "enabled" : "disabled" : "not present");
|
||||
BootPrint(s);
|
||||
|
||||
#if 0
|
||||
if (cluster_size < 64)
|
||||
{
|
||||
BootPrint("\n***************************************************");
|
||||
BootPrint( "* It's recommended to reformat your memory card *");
|
||||
BootPrint( "* using 32 KB clusters to improve performance *");
|
||||
BootPrint( "* when using large hardfiles. *"); // AMR
|
||||
BootPrint( "***************************************************");
|
||||
}
|
||||
printf("Bootloading is complete.\r");
|
||||
#endif
|
||||
|
||||
BootPrint("\nExiting bootloader...");
|
||||
|
||||
ConfigMemory(config.memory);
|
||||
ConfigCPU(config.cpu);
|
||||
ConfigFilter(config.filter.lores, config.filter.hires);
|
||||
ConfigScanlines(config.scanlines);
|
||||
|
||||
if(reloadkickstart)
|
||||
{
|
||||
WaitTimer(5000);
|
||||
BootExit();
|
||||
}
|
||||
else
|
||||
OsdReset(RESET_NORMAL);
|
||||
|
||||
ConfigChipset(config.chipset);
|
||||
ConfigFloppy(config.floppy.drives, config.floppy.speed);
|
||||
}
|
||||
|
||||
|
||||
unsigned char SaveConfiguration(char *filename)
|
||||
{
|
||||
if(!filename)
|
||||
filename=configfilename; // Use slot-based filename if none provided.
|
||||
|
||||
// save configuration data
|
||||
if (FileOpen(&file, filename))
|
||||
{
|
||||
printf("Configuration file size: %lu\r", file.size);
|
||||
if (file.size != sizeof(config))
|
||||
{
|
||||
file.size = sizeof(config);
|
||||
if (!UpdateEntry(&file))
|
||||
return(0);
|
||||
}
|
||||
|
||||
memset((void*)§or_buffer, 0, sizeof(sector_buffer));
|
||||
memcpy((void*)§or_buffer, (void*)&config, sizeof(config));
|
||||
FileWrite(&file, sector_buffer);
|
||||
return(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Configuration file not found!\r");
|
||||
printf("Trying to create a new one...\r");
|
||||
strncpy(file.name, filename, 11);
|
||||
file.attributes = 0;
|
||||
file.size = sizeof(config);
|
||||
if (FileCreate(0, &file))
|
||||
{
|
||||
printf("File created.\r");
|
||||
printf("Trying to write new data...\r");
|
||||
memset((void*)sector_buffer, 0, sizeof(sector_buffer));
|
||||
memcpy((void*)sector_buffer, (void*)&config, sizeof(config));
|
||||
|
||||
if (FileWrite(&file, sector_buffer))
|
||||
{
|
||||
printf("File written successfully.\r");
|
||||
return(1);
|
||||
}
|
||||
else
|
||||
printf("File write failed!\r");
|
||||
}
|
||||
else
|
||||
printf("File creation failed!\r");
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
60
config.h
Normal file
60
config.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#include "fat.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[8];
|
||||
char long_name[16];
|
||||
} kickstartTYPE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char lores;
|
||||
unsigned char hires;
|
||||
} filterTYPE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char speed;
|
||||
unsigned char drives;
|
||||
} floppyTYPE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char enabled; // 0: Disabled, 1: Hard file, 2: MMC (entire card), 3-6: Partition 1-4 of MMC card
|
||||
unsigned char present;
|
||||
char name[8];
|
||||
char long_name[16];
|
||||
} hardfileTYPE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char id[8];
|
||||
unsigned long version;
|
||||
kickstartTYPE kickstart;
|
||||
filterTYPE filter;
|
||||
unsigned char memory;
|
||||
unsigned char chipset;
|
||||
floppyTYPE floppy;
|
||||
unsigned char disable_ar3;
|
||||
unsigned char enable_ide;
|
||||
unsigned char scanlines;
|
||||
unsigned char pad1;
|
||||
hardfileTYPE hardfile[2];
|
||||
unsigned char cpu;
|
||||
unsigned char pad2;
|
||||
} configTYPE;
|
||||
|
||||
extern fileTYPE file; // Temporary file available for use by other modules, to avoid repeated memory usage.
|
||||
// Shouldn't be considered persistent.
|
||||
|
||||
extern configTYPE config;
|
||||
extern char DebugMode;
|
||||
|
||||
char UploadKickstart(char *name);
|
||||
char UploadActionReplay();
|
||||
void SetConfigurationFilename(int config); // Set configuration filename by slot number
|
||||
unsigned char LoadConfiguration(char *filename); // Can supply NULL to use filename previously set by slot number
|
||||
unsigned char SaveConfiguration(char *filename); // Can supply NULL to use filename previously set by slot number
|
||||
unsigned char ConfigurationExists(char *filename);
|
||||
void ApplyConfiguration(char reloadkickstart);
|
||||
|
||||
9
errors.h
Normal file
9
errors.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#define ERROR_NONE 0
|
||||
#define ERROR_FILE_NOT_FOUND 1
|
||||
#define ERROR_INVALID_DATA 2
|
||||
#define ERROR_UPDATE_FAILED 3
|
||||
|
||||
extern unsigned char Error;
|
||||
|
||||
void ErrorMessage(const char *message, unsigned char code);
|
||||
void FatalError(unsigned long error);
|
||||
128
fat.h
Normal file
128
fat.h
Normal file
@@ -0,0 +1,128 @@
|
||||
#ifndef _FAT16_H_INCLUDED
|
||||
#define _FAT16_H_INCLUDED
|
||||
|
||||
#include "hardware.h"
|
||||
|
||||
#define MAXDIRENTRIES 8
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned long sector;
|
||||
unsigned long index;
|
||||
} entryTYPE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[11]; /* name of file */
|
||||
unsigned char attributes; /* file attributes */
|
||||
entryTYPE entry; /* file entry location */
|
||||
unsigned long sector; /* sector index in file */
|
||||
unsigned long size; /* file size */
|
||||
unsigned long cluster; /* current cluster */
|
||||
unsigned long start_cluster; /* first cluster of file */
|
||||
char long_name[261];
|
||||
} fileTYPE;
|
||||
|
||||
struct PartitionEntry
|
||||
{
|
||||
unsigned char geometry[8]; // ignored
|
||||
unsigned long startlba;
|
||||
unsigned long sectors;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct MasterBootRecord
|
||||
{
|
||||
unsigned char bootcode[446]; // ignored
|
||||
struct PartitionEntry Partition[4]; // We copy these (and byteswap if need be)
|
||||
unsigned short Signature; // This lets us detect an MBR (and the need for byteswapping).
|
||||
} __attribute__ ((packed));
|
||||
|
||||
extern struct PartitionEntry partitions[4]; // FirstBlock and LastBlock will be byteswapped as necessary
|
||||
extern int partitioncount;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char Name[8]; /* filename, blank filled */
|
||||
#define SLOT_EMPTY 0x00 /* slot has never been used */
|
||||
#define SLOT_E5 0x05 /* the real value is 0xe5 */
|
||||
#define SLOT_DELETED 0xe5 /* file in this slot deleted */
|
||||
unsigned char Extension[3]; /* extension, blank filled */
|
||||
unsigned char Attributes; /* file attributes */
|
||||
#define ATTR_NORMAL 0x00 /* normal file */
|
||||
#define ATTR_READONLY 0x01 /* file is readonly */
|
||||
#define ATTR_HIDDEN 0x02 /* file is hidden */
|
||||
#define ATTR_SYSTEM 0x04 /* file is a system file */
|
||||
#define ATTR_VOLUME 0x08 /* entry is a volume label */
|
||||
#define ATTR_DIRECTORY 0x10 /* entry is a directory name */
|
||||
#define ATTR_ARCHIVE 0x20 /* file is new or modified */
|
||||
#define ATTR_LFN 0x0F /* long file name entry */
|
||||
unsigned char LowerCase; /* NT VFAT lower case flags */
|
||||
#define LCASE_BASE 0x08 /* filename base in lower case */
|
||||
#define LCASE_EXT 0x10 /* filename extension in lower case */
|
||||
unsigned char CreateHundredth; /* hundredth of seconds in CTime */
|
||||
unsigned short CreateTime; /* create time */
|
||||
unsigned short CreateDate; /* create date */
|
||||
unsigned short AccessDate; /* access date */
|
||||
unsigned short HighCluster; /* high bytes of cluster number */
|
||||
unsigned short ModifyTime; /* last update time */
|
||||
unsigned short ModifyDate; /* last update date */
|
||||
unsigned short StartCluster; /* starting cluster of file */
|
||||
unsigned long FileSize; /* size of file in bytes */
|
||||
} DIRENTRY;
|
||||
|
||||
typedef union {
|
||||
unsigned short fat16[256];
|
||||
unsigned long fat32[128];
|
||||
} FATBUFFER;
|
||||
|
||||
#define FILETIME(h,m,s) (((h<<11)&0xF800)|((m<<5)&0x7E0)|((s/2)&0x1F))
|
||||
#define FILEDATE(y,m,d) ((((y-1980)<<9)&0xFE00)|((m<<5)&0x1E0)|(d&0x1F))
|
||||
|
||||
// global sector buffer, data for read/write actions is stored here.
|
||||
// BEWARE, this buffer is also used and thus trashed by all other functions
|
||||
extern unsigned char sector_buffer[1024]; // sector buffer - room for 2 sectors, to ease reading data not sector-aligned...
|
||||
extern unsigned char cluster_size;
|
||||
extern unsigned long cluster_mask;
|
||||
extern unsigned char fat32;
|
||||
|
||||
// constants
|
||||
#define DIRECTORY_ROOT 0
|
||||
|
||||
// file seeking
|
||||
#define SEEK_SET 0
|
||||
#define SEEK_CUR 1
|
||||
|
||||
// scanning flags
|
||||
#define SCAN_INIT 0 // start search from beginning of directory
|
||||
#define SCAN_NEXT 1 // find next file in directory
|
||||
#define SCAN_PREV -1 // find previous file in directory
|
||||
#define SCAN_NEXT_PAGE 2 // find next 8 files in directory
|
||||
#define SCAN_PREV_PAGE -2 // find previous 8 files in directory
|
||||
#define SCAN_INIT_FIRST 3 // search for an entry with given cluster number
|
||||
#define SCAN_INIT_NEXT 4 // search for entries higher than the first one
|
||||
|
||||
// options flags
|
||||
#define SCAN_DIR 1 // include subdirectories
|
||||
#define SCAN_LFN 2 // include long file names
|
||||
#define FIND_DIR 4 // find first directory beginning with given charater
|
||||
#define FIND_FILE 8 // find first file entry beginning with given charater
|
||||
|
||||
|
||||
// functions
|
||||
unsigned char FindDrive(void);
|
||||
unsigned long GetFATLink(unsigned long cluster);
|
||||
unsigned char FileNextSector(fileTYPE *file) RAMFUNC;
|
||||
unsigned char FileOpen(fileTYPE *file, const char *name);
|
||||
unsigned char FileSeek(fileTYPE *file, unsigned long offset, unsigned long origin);
|
||||
unsigned char FileRead(fileTYPE *file, unsigned char *pBuffer) RAMFUNC;
|
||||
unsigned char FileWrite(fileTYPE *file, unsigned char *pBuffer);
|
||||
unsigned char FileReadEx(fileTYPE *file, unsigned char *pBuffer, unsigned long nSize);
|
||||
|
||||
unsigned char FileCreate(unsigned long iDirectory, fileTYPE *file);
|
||||
unsigned char UpdateEntry(fileTYPE *file);
|
||||
|
||||
char ScanDirectory(unsigned long mode, char *extension, unsigned char options);
|
||||
void ChangeDirectory(unsigned long iStartCluster);
|
||||
|
||||
#endif
|
||||
|
||||
701
fdd.c
Normal file
701
fdd.c
Normal file
@@ -0,0 +1,701 @@
|
||||
/*
|
||||
Copyright 2005, 2006, 2007 Dennis van Weeren
|
||||
Copyright 2008, 2009 Jakub Bednarski
|
||||
|
||||
This file is part of Minimig
|
||||
|
||||
Minimig is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Minimig is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// 2009-11-14 - adapted gap size
|
||||
// 2009-12-24 - updated sync word list
|
||||
// - fixed sector header generation
|
||||
// 2010-01-09 - support for variable number of tracks
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include "AT91SAM7S256.h"
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "errors.h"
|
||||
#include "hardware.h"
|
||||
#include "fat.h"
|
||||
#include "fdd.h"
|
||||
#include "config.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define SPIN
|
||||
extern fileTYPE file;
|
||||
#endif
|
||||
|
||||
unsigned char vDEBUG = 0;
|
||||
|
||||
unsigned char drives = 0; // number of active drives reported by FPGA (may change only during reset)
|
||||
adfTYPE *pdfx; // drive select pointer
|
||||
adfTYPE df[4]; // drive 0 information structure
|
||||
|
||||
#define TRACK_SIZE 12668
|
||||
#define HEADER_SIZE 0x40
|
||||
#define DATA_SIZE 0x400
|
||||
#define SECTOR_SIZE (HEADER_SIZE + DATA_SIZE)
|
||||
#define SECTOR_COUNT 11
|
||||
#define LAST_SECTOR (SECTOR_COUNT - 1)
|
||||
#define GAP_SIZE (TRACK_SIZE - SECTOR_COUNT * SECTOR_SIZE)
|
||||
|
||||
// sends the data in the sector buffer to the FPGA, translated into an Amiga floppy format sector
|
||||
// note that we do not insert clock bits because they will be stripped by the Amiga software anyway
|
||||
void SendSector(unsigned char *pData, unsigned char sector, unsigned char track, unsigned char dsksynch, unsigned char dsksyncl)
|
||||
{
|
||||
unsigned char checksum[4];
|
||||
unsigned short i;
|
||||
unsigned char x;
|
||||
unsigned char *p;
|
||||
|
||||
// preamble
|
||||
SPI(0xAA);
|
||||
SPI(0xAA);
|
||||
SPI(0xAA);
|
||||
SPI(0xAA);
|
||||
|
||||
// synchronization
|
||||
SPI(dsksynch);
|
||||
SPI(dsksyncl);
|
||||
SPI(dsksynch);
|
||||
SPI(dsksyncl);
|
||||
|
||||
// odd bits of header
|
||||
x = 0x55;
|
||||
checksum[0] = x;
|
||||
SPI(x);
|
||||
x = track >> 1 & 0x55;
|
||||
checksum[1] = x;
|
||||
SPI(x);
|
||||
x = sector >> 1 & 0x55;
|
||||
checksum[2] = x;
|
||||
SPI(x);
|
||||
x = 11 - sector >> 1 & 0x55;
|
||||
checksum[3] = x;
|
||||
SPI(x);
|
||||
|
||||
// even bits of header
|
||||
x = 0x55;
|
||||
checksum[0] ^= x;
|
||||
SPI(x);
|
||||
x = track & 0x55;
|
||||
checksum[1] ^= x;
|
||||
SPI(x);
|
||||
x = sector & 0x55;
|
||||
checksum[2] ^= x;
|
||||
SPI(x);
|
||||
x = 11 - sector & 0x55;
|
||||
checksum[3] ^= x;
|
||||
SPI(x);
|
||||
|
||||
// sector label and reserved area (changes nothing to checksum)
|
||||
i = 0x20;
|
||||
while (i--)
|
||||
SPI(0xAA);
|
||||
|
||||
// send header checksum
|
||||
SPI(0xAA);
|
||||
SPI(0xAA);
|
||||
SPI(0xAA);
|
||||
SPI(0xAA);
|
||||
SPI(checksum[0] | 0xAA);
|
||||
SPI(checksum[1] | 0xAA);
|
||||
SPI(checksum[2] | 0xAA);
|
||||
SPI(checksum[3] | 0xAA);
|
||||
|
||||
// calculate data checksum
|
||||
checksum[0] = 0;
|
||||
checksum[1] = 0;
|
||||
checksum[2] = 0;
|
||||
checksum[3] = 0;
|
||||
|
||||
p = pData;
|
||||
i = DATA_SIZE / 2 / 4;
|
||||
while (i--)
|
||||
{
|
||||
x = *p++;
|
||||
checksum[0] ^= x ^ x >> 1;
|
||||
x = *p++;
|
||||
checksum[1] ^= x ^ x >> 1;
|
||||
x = *p++;
|
||||
checksum[2] ^= x ^ x >> 1;
|
||||
x = *p++;
|
||||
checksum[3] ^= x ^ x >> 1;
|
||||
}
|
||||
|
||||
// send data checksum
|
||||
SPI(0xAA);
|
||||
SPI(0xAA);
|
||||
SPI(0xAA);
|
||||
SPI(0xAA);
|
||||
SPI(checksum[0] | 0xAA);
|
||||
SPI(checksum[1] | 0xAA);
|
||||
SPI(checksum[2] | 0xAA);
|
||||
SPI(checksum[3] | 0xAA);
|
||||
|
||||
// odd bits of data field
|
||||
i = DATA_SIZE / 2;
|
||||
p = pData;
|
||||
while (i--)
|
||||
SPI(*p++ >> 1 | 0xAA);
|
||||
|
||||
// even bits of data field
|
||||
i = DATA_SIZE / 2;
|
||||
p = pData;
|
||||
while (i--)
|
||||
SPI(*p++ | 0xAA);
|
||||
}
|
||||
|
||||
void SendGap(void)
|
||||
{
|
||||
unsigned short i = GAP_SIZE;
|
||||
while (i--)
|
||||
SPI(0xAA);
|
||||
}
|
||||
|
||||
// read a track from disk
|
||||
void ReadTrack(adfTYPE *drive)
|
||||
{ // track number is updated in drive struct before calling this function
|
||||
|
||||
unsigned char sector;
|
||||
unsigned char status;
|
||||
unsigned char track;
|
||||
unsigned short dsksync;
|
||||
unsigned short dsklen;
|
||||
//unsigned short n;
|
||||
|
||||
if (drive->track >= drive->tracks)
|
||||
{
|
||||
printf("Illegal track read: %d\r", drive->track);
|
||||
ErrorMessage(" Illegal track read!", drive->track);
|
||||
drive->track = drive->tracks - 1;
|
||||
}
|
||||
|
||||
// display track number: cylinder & head
|
||||
if (vDEBUG)
|
||||
printf("*%u:", drive->track);
|
||||
|
||||
if (drive->track != drive->track_prev)
|
||||
{ // track step or track 0, start at beginning of track
|
||||
drive->track_prev = drive->track;
|
||||
sector = 0;
|
||||
file.cluster = drive->cache[drive->track];
|
||||
file.sector = drive->track * SECTOR_COUNT;
|
||||
drive->sector_offset = sector;
|
||||
drive->cluster_offset = file.cluster;
|
||||
}
|
||||
else
|
||||
{ // same track, start at next sector in track
|
||||
sector = drive->sector_offset;
|
||||
file.cluster = drive->cluster_offset;
|
||||
file.sector = (drive->track * SECTOR_COUNT) + sector;
|
||||
}
|
||||
|
||||
EnableFpga();
|
||||
status = SPI(0); // read request signal
|
||||
track = SPI(0); // track number (cylinder & head)
|
||||
dsksync = (SPI(0)) << 8; // disk sync high byte
|
||||
dsksync |= SPI(0); // disk sync low byte
|
||||
dsklen = (SPI(0)) << 8 & 0x3F00; // msb of mfm words to transfer
|
||||
dsklen |= SPI(0); // lsb of mfm words to transfer
|
||||
DisableFpga();
|
||||
|
||||
if (track >= drive->tracks)
|
||||
track = drive->tracks - 1;
|
||||
|
||||
if (vDEBUG)
|
||||
printf("(%u)[%04X]:", status >> 6, dsksync);
|
||||
|
||||
while (1)
|
||||
{
|
||||
FileRead(&file, sector_buffer);
|
||||
|
||||
EnableFpga();
|
||||
|
||||
// check if FPGA is still asking for data
|
||||
status = SPI(0); // read request signal
|
||||
track = SPI(0); // track number (cylinder & head)
|
||||
dsksync = (SPI(0)) << 8; // disk sync high byte
|
||||
dsksync |= SPI(0); // disk sync low byte
|
||||
dsklen = (SPI(0)) << 8 & 0x3F00; // msb of mfm words to transfer
|
||||
dsklen |= SPI(0); // lsb of mfm words to transfer
|
||||
|
||||
if (track >= drive->tracks)
|
||||
track = drive->tracks - 1;
|
||||
|
||||
// workaround for Copy Lock in Wiz'n'Liz and North&South (might brake other games)
|
||||
if (dsksync == 0x0000 || dsksync == 0x8914 || dsksync == 0xA144)
|
||||
dsksync = 0x4489;
|
||||
|
||||
// North&South: $A144
|
||||
// Wiz'n'Liz (Copy Lock): $8914
|
||||
// Prince of Persia: $4891
|
||||
// Commando: $A245
|
||||
|
||||
if (vDEBUG)
|
||||
printf("%X:%04X", sector, dsklen);
|
||||
|
||||
// some loaders stop dma if sector header isn't what they expect
|
||||
// because we don't check dma transfer count after sending a word
|
||||
// the track can be changed while we are sending the rest of the previous sector
|
||||
// in this case let's start transfer from the beginning
|
||||
if (track == drive->track)
|
||||
{
|
||||
// send sector if fpga is still asking for data
|
||||
if (status & CMD_RDTRK)
|
||||
{
|
||||
//GenerateHeader(sector_header, sector_buffer, sector, track, dsksync);
|
||||
//SendSector(sector_header, sector_buffer);
|
||||
SendSector(sector_buffer, sector, track, (unsigned char)(dsksync >> 8), (unsigned char)dsksync);
|
||||
|
||||
if (sector == LAST_SECTOR)
|
||||
SendGap();
|
||||
}
|
||||
}
|
||||
|
||||
// we are done accessing FPGA
|
||||
DisableFpga();
|
||||
|
||||
// track has changed
|
||||
if (track != drive->track)
|
||||
break;
|
||||
|
||||
// read dma request
|
||||
if (!(status & CMD_RDTRK))
|
||||
break;
|
||||
|
||||
sector++;
|
||||
if (sector < SECTOR_COUNT)
|
||||
{
|
||||
FileNextSector(&file);
|
||||
}
|
||||
else // go to the start of current track
|
||||
{
|
||||
sector = 0;
|
||||
file.cluster = drive->cache[drive->track];
|
||||
file.sector = drive->track * SECTOR_COUNT;
|
||||
}
|
||||
|
||||
// remember current sector and cluster
|
||||
drive->sector_offset = sector;
|
||||
drive->cluster_offset = file.cluster;
|
||||
|
||||
if (vDEBUG)
|
||||
printf("->");
|
||||
}
|
||||
if (vDEBUG)
|
||||
printf(":OK\r");
|
||||
}
|
||||
|
||||
unsigned char FindSync(adfTYPE *drive)
|
||||
// reads data from fifo till it finds sync word or fifo is empty and dma inactive (so no more data is expected)
|
||||
{
|
||||
unsigned char c1, c2, c3, c4;
|
||||
unsigned short n;
|
||||
|
||||
while (1)
|
||||
{
|
||||
EnableFpga();
|
||||
c1 = SPI(0); // write request signal
|
||||
c2 = SPI(0); // track number (cylinder & head)
|
||||
if (!(c1 & CMD_WRTRK))
|
||||
break;
|
||||
if (c2 != drive->track)
|
||||
break;
|
||||
SPI(0); // disk sync high byte
|
||||
SPI(0); // disk sync low byte
|
||||
c3 = (SPI(0)) & 0xBF; // msb of mfm words to transfer
|
||||
c4 = SPI(0); // lsb of mfm words to transfer
|
||||
|
||||
if (c3 == 0 && c4 == 0)
|
||||
break;
|
||||
|
||||
n = ((c3 & 0x3F) << 8) + c4;
|
||||
|
||||
while (n--)
|
||||
{
|
||||
c3 = SPI(0);
|
||||
c4 = SPI(0);
|
||||
if (c3 == 0x44 && c4 == 0x89)
|
||||
{
|
||||
DisableFpga();
|
||||
if (vDEBUG)
|
||||
printf("#SYNC:");
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
DisableFpga();
|
||||
}
|
||||
DisableFpga();
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char GetHeader(unsigned char *pTrack, unsigned char *pSector)
|
||||
// this function reads data from fifo till it finds sync word or dma is inactive
|
||||
{
|
||||
unsigned char c, c1, c2, c3, c4;
|
||||
unsigned char i;
|
||||
unsigned char checksum[4];
|
||||
|
||||
Error = 0;
|
||||
while (1)
|
||||
{
|
||||
EnableFpga();
|
||||
c1 = SPI(0); // write request signal
|
||||
c2 = SPI(0); // track number (cylinder & head)
|
||||
if (!(c1 & CMD_WRTRK))
|
||||
break;
|
||||
SPI(0); // disk sync high byte
|
||||
SPI(0); // disk sync low byte
|
||||
c3 = SPI(0); // msb of mfm words to transfer
|
||||
c4 = SPI(0); // lsb of mfm words to transfer
|
||||
|
||||
if ((c3 & 0x3F) != 0 || c4 > 24)// remaining header data is 25 mfm words
|
||||
{
|
||||
c1 = SPI(0); // second sync lsb
|
||||
c2 = SPI(0); // second sync msb
|
||||
if (c1 != 0x44 || c2 != 0x89)
|
||||
{
|
||||
Error = 21;
|
||||
printf("\rSecond sync word missing...\r");
|
||||
break;
|
||||
}
|
||||
|
||||
SPIN;
|
||||
|
||||
c = SPI(0);
|
||||
checksum[0] = c;
|
||||
c1 = (c & 0x55) << 1;
|
||||
SPIN;
|
||||
c = SPI(0);
|
||||
checksum[1] = c;
|
||||
c2 = (c & 0x55) << 1;
|
||||
|
||||
SPIN;
|
||||
|
||||
c = SPI(0);
|
||||
checksum[2] = c;
|
||||
c3 = (c & 0x55) << 1;
|
||||
SPIN;
|
||||
c = SPI(0);
|
||||
checksum[3] = c;
|
||||
c4 = (c & 0x55) << 1;
|
||||
|
||||
SPIN;
|
||||
|
||||
c = SPI(0);
|
||||
checksum[0] ^= c;
|
||||
c1 |= c & 0x55;
|
||||
SPIN;
|
||||
c = SPI(0);
|
||||
checksum[1] ^= c;
|
||||
c2 |= c & 0x55;
|
||||
|
||||
SPIN;
|
||||
|
||||
c = SPI(0);
|
||||
checksum[2] ^= c;
|
||||
c3 |= c & 0x55;
|
||||
SPIN;
|
||||
c = SPI(0);
|
||||
checksum[3] ^= c;
|
||||
c4 |= c & 0x55;
|
||||
|
||||
if (c1 != 0xFF) // always 0xFF
|
||||
Error = 22;
|
||||
else if (c2 > 159) // Track number (0-159)
|
||||
Error = 23;
|
||||
else if (c3 > 10) // Sector number (0-10)
|
||||
Error = 24;
|
||||
else if (c4 > 11 || c4 == 0) // Number of sectors to gap (1-11)
|
||||
Error = 25;
|
||||
|
||||
if (Error)
|
||||
{
|
||||
printf("\rWrong header: %u.%u.%u.%u\r", c1, c2, c3, c4);
|
||||
break;
|
||||
}
|
||||
|
||||
if (vDEBUG)
|
||||
printf("T%uS%u\r", c2, c3);
|
||||
|
||||
*pTrack = c2;
|
||||
*pSector = c3;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
SPIN;
|
||||
checksum[0] ^= SPI(0);
|
||||
checksum[1] ^= SPI(0);
|
||||
SPIN;
|
||||
checksum[2] ^= SPI(0);
|
||||
checksum[3] ^= SPI(0);
|
||||
}
|
||||
|
||||
checksum[0] &= 0x55;
|
||||
checksum[1] &= 0x55;
|
||||
checksum[2] &= 0x55;
|
||||
checksum[3] &= 0x55;
|
||||
|
||||
SPIN;
|
||||
|
||||
c1 = ((SPI(0)) & 0x55) << 1;
|
||||
c2 = ((SPI(0)) & 0x55) << 1;
|
||||
SPIN;
|
||||
c3 = ((SPI(0)) & 0x55) << 1;
|
||||
c4 = ((SPI(0)) & 0x55) << 1;
|
||||
|
||||
SPIN;
|
||||
|
||||
c1 |= (SPI(0)) & 0x55;
|
||||
c2 |= (SPI(0)) & 0x55;
|
||||
SPIN;
|
||||
c3 |= (SPI(0)) & 0x55;
|
||||
c4 |= (SPI(0)) & 0x55;
|
||||
|
||||
if (c1 != checksum[0] || c2 != checksum[1] || c3 != checksum[2] || c4 != checksum[3])
|
||||
{
|
||||
Error = 26;
|
||||
break;
|
||||
}
|
||||
|
||||
DisableFpga();
|
||||
return 1;
|
||||
}
|
||||
else if ((c3 & 0x80) == 0) // not enough data for header and write dma is not active
|
||||
{
|
||||
Error = 20;
|
||||
break;
|
||||
}
|
||||
|
||||
DisableFpga();
|
||||
}
|
||||
|
||||
DisableFpga();
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char GetData(void)
|
||||
{
|
||||
unsigned char c, c1, c2, c3, c4;
|
||||
unsigned char i;
|
||||
unsigned char *p;
|
||||
unsigned short n;
|
||||
unsigned char checksum[4];
|
||||
|
||||
Error = 0;
|
||||
while (1)
|
||||
{
|
||||
EnableFpga();
|
||||
c1 = SPI(0); // write request signal
|
||||
c2 = SPI(0); // track number (cylinder & head)
|
||||
if (!(c1 & CMD_WRTRK))
|
||||
break;
|
||||
SPI(0); // disk sync high byte
|
||||
SPI(0); // disk sync low byte
|
||||
c3 = SPI(0); // msb of mfm words to transfer
|
||||
c4 = SPI(0); // lsb of mfm words to transfer
|
||||
|
||||
n = ((c3 & 0x3F) << 8) + c4;
|
||||
|
||||
if (n >= 0x204)
|
||||
{
|
||||
SPIN;
|
||||
|
||||
c1 = ((SPI(0)) & 0x55) << 1;
|
||||
c2 = ((SPI(0)) & 0x55) << 1;
|
||||
SPIN;
|
||||
c3 = ((SPI(0)) & 0x55) << 1;
|
||||
c4 = ((SPI(0)) & 0x55) << 1;
|
||||
|
||||
SPIN;
|
||||
|
||||
c1 |= (SPI(0)) & 0x55;
|
||||
c2 |= (SPI(0)) & 0x55;
|
||||
SPIN;
|
||||
c3 |= (SPI(0)) & 0x55;
|
||||
c4 |= (SPI(0)) & 0x55;
|
||||
|
||||
checksum[0] = 0;
|
||||
checksum[1] = 0;
|
||||
checksum[2] = 0;
|
||||
checksum[3] = 0;
|
||||
|
||||
// odd bits of data field
|
||||
i = 128;
|
||||
p = sector_buffer;
|
||||
do
|
||||
{
|
||||
SPIN;
|
||||
c = SPI(0);
|
||||
checksum[0] ^= c;
|
||||
*p++ = (c & 0x55) << 1;
|
||||
c = SPI(0);
|
||||
checksum[1] ^= c;
|
||||
*p++ = (c & 0x55) << 1;
|
||||
SPIN;
|
||||
c = SPI(0);
|
||||
checksum[2] ^= c;
|
||||
*p++ = (c & 0x55) << 1;
|
||||
c = SPI(0);
|
||||
checksum[3] ^= c;
|
||||
*p++ = (c & 0x55) << 1;
|
||||
}
|
||||
while (--i);
|
||||
|
||||
// even bits of data field
|
||||
i = 128;
|
||||
p = sector_buffer;
|
||||
do
|
||||
{
|
||||
SPIN;
|
||||
c = SPI(0);
|
||||
checksum[0] ^= c;
|
||||
*p++ |= c & 0x55;
|
||||
c = SPI(0);
|
||||
checksum[1] ^= c;
|
||||
*p++ |= c & 0x55;
|
||||
SPIN;
|
||||
c = SPI(0);
|
||||
checksum[2] ^= c;
|
||||
*p++ |= c & 0x55;
|
||||
c = SPI(0);
|
||||
checksum[3] ^= c;
|
||||
*p++ |= c & 0x55;
|
||||
}
|
||||
while (--i);
|
||||
|
||||
checksum[0] &= 0x55;
|
||||
checksum[1] &= 0x55;
|
||||
checksum[2] &= 0x55;
|
||||
checksum[3] &= 0x55;
|
||||
|
||||
if (c1 != checksum[0] || c2 != checksum[1] || c3 != checksum[2] || c4 != checksum[3])
|
||||
{
|
||||
Error = 29;
|
||||
break;
|
||||
}
|
||||
|
||||
DisableFpga();
|
||||
return 1;
|
||||
}
|
||||
else if ((c3 & 0x80) == 0) // not enough data in fifo and write dma is not active
|
||||
{
|
||||
Error = 28;
|
||||
break;
|
||||
}
|
||||
|
||||
DisableFpga();
|
||||
}
|
||||
DisableFpga();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WriteTrack(adfTYPE *drive)
|
||||
{
|
||||
unsigned char sector;
|
||||
unsigned char Track;
|
||||
unsigned char Sector;
|
||||
|
||||
// setting file pointer to begining of current track
|
||||
file.cluster = drive->cache[drive->track];
|
||||
file.sector = drive->track * 11;
|
||||
sector = 0;
|
||||
|
||||
drive->track_prev = drive->track + 1; // just to force next read from the start of current track
|
||||
|
||||
if (vDEBUG)
|
||||
printf("*%u:\r", drive->track);
|
||||
|
||||
while (FindSync(drive))
|
||||
{
|
||||
if (GetHeader(&Track, &Sector))
|
||||
{
|
||||
if (Track == drive->track)
|
||||
{
|
||||
while (sector != Sector)
|
||||
{
|
||||
if (sector < Sector)
|
||||
{
|
||||
FileNextSector(&file);
|
||||
sector++;
|
||||
}
|
||||
else
|
||||
{
|
||||
file.cluster = drive->cache[drive->track];
|
||||
file.sector = drive->track * 11;
|
||||
sector = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (GetData())
|
||||
{
|
||||
if (drive->status & DSK_WRITABLE)
|
||||
FileWrite(&file, sector_buffer);
|
||||
else
|
||||
{
|
||||
Error = 30;
|
||||
printf("Write attempt to protected disk!\r");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
Error = 27; //track number reported in sector header is not the same as current drive track
|
||||
}
|
||||
if (Error)
|
||||
{
|
||||
printf("WriteTrack: error %u\r", Error);
|
||||
ErrorMessage(" WriteTrack", Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateDriveStatus(void)
|
||||
{
|
||||
EnableFpga();
|
||||
SPI(0x10);
|
||||
SPI(df[0].status | (df[1].status << 1) | (df[2].status << 2) | (df[3].status << 3));
|
||||
DisableFpga();
|
||||
}
|
||||
|
||||
void HandleFDD(unsigned char c1, unsigned char c2)
|
||||
{
|
||||
unsigned char sel;
|
||||
drives = (c1 >> 4) & 0x03; // number of active floppy drives
|
||||
|
||||
if (c1 & CMD_RDTRK)
|
||||
{
|
||||
DISKLED_ON;
|
||||
sel = (c1 >> 6) & 0x03;
|
||||
df[sel].track = c2;
|
||||
ReadTrack(&df[sel]);
|
||||
DISKLED_OFF;
|
||||
}
|
||||
else if (c1 & CMD_WRTRK)
|
||||
{
|
||||
DISKLED_ON;
|
||||
sel = (c1 >> 6) & 0x03;
|
||||
df[sel].track = c2;
|
||||
WriteTrack(&df[sel]);
|
||||
DISKLED_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
38
fdd.h
Normal file
38
fdd.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef FDD_H
|
||||
#define FDD_H
|
||||
|
||||
// floppy disk interface defs
|
||||
#define CMD_RDTRK 0x01
|
||||
#define CMD_WRTRK 0x02
|
||||
|
||||
// floppy status
|
||||
#define DSK_INSERTED 0x01 /*disk is inserted*/
|
||||
#define DSK_WRITABLE 0x10 /*disk is writable*/
|
||||
|
||||
#define MAX_TRACKS (83*2)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char status; /*status of floppy*/
|
||||
unsigned char tracks; /*number of tracks*/
|
||||
unsigned long cache[MAX_TRACKS]; /*cluster cache*/
|
||||
unsigned long cluster_offset; /*cluster offset to handle tricky loaders*/
|
||||
unsigned char sector_offset; /*sector offset to handle tricky loaders*/
|
||||
unsigned char track; /*current track*/
|
||||
unsigned char track_prev; /*previous track*/
|
||||
char name[22]; /*floppy name*/
|
||||
} adfTYPE;
|
||||
|
||||
void SectorGapToFpga(void);
|
||||
void SectorHeaderToFpga(unsigned char n, unsigned char dsksynch, unsigned char dsksyncl);
|
||||
//unsigned short SectorToFpga(unsigned char sector, unsigned char track, unsigned char dsksynch, unsigned char dsksyncl);
|
||||
void ReadTrack(adfTYPE *drive);
|
||||
unsigned char FindSync(adfTYPE *drive);
|
||||
unsigned char GetHeader(unsigned char *pTrack, unsigned char *pSector);
|
||||
unsigned char GetData(void);
|
||||
void WriteTrack(adfTYPE *drive);
|
||||
void UpdateDriveStatus(void);
|
||||
void HandleFDD(unsigned char c1, unsigned char c2);
|
||||
|
||||
#endif
|
||||
|
||||
224
firmware.c
Normal file
224
firmware.c
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
Copyright 2008, 2009 Jakub Bednarski
|
||||
|
||||
This file is part of Minimig
|
||||
|
||||
Minimig is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Minimig is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "AT91SAM7S256.h"
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
#include "errors.h"
|
||||
#include "hardware.h"
|
||||
#include "fat.h"
|
||||
#include "firmware.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define __noinline
|
||||
#endif
|
||||
|
||||
/* polynomial 0xEDB88320 */
|
||||
const unsigned long crc32_table[256] =
|
||||
{
|
||||
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
||||
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
||||
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
||||
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
||||
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
||||
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
||||
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
||||
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
||||
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
||||
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
||||
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
||||
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
||||
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
||||
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
||||
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
||||
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
||||
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
||||
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
||||
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
||||
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
||||
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
||||
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
||||
};
|
||||
|
||||
// Initial CRC value is -1 (0xFFFFFFFF)
|
||||
// Final CRC value is bitwise negation of the last calculated value
|
||||
unsigned long CalculateCRC32(unsigned long crc, unsigned char *pBuffer, unsigned long nSize)
|
||||
{
|
||||
while (nSize--)
|
||||
crc = crc32_table[(unsigned char)crc ^ *pBuffer++] ^ crc >> 8;
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
unsigned char CheckFirmware(fileTYPE *file, char *name)
|
||||
{
|
||||
UPGRADE *pUpgrade = (UPGRADE*)sector_buffer;
|
||||
unsigned long crc;
|
||||
unsigned long size;
|
||||
unsigned long rom_size;
|
||||
unsigned long rom_crc;
|
||||
unsigned long read_size;
|
||||
|
||||
Error = ERROR_FILE_NOT_FOUND;
|
||||
if (FileOpen(file, name))
|
||||
{
|
||||
Error = ERROR_INVALID_DATA;
|
||||
printf("Upgrade file size : %lu\r", file->size);
|
||||
printf("Upgrade header size : %lu\r", (unsigned long)sizeof(UPGRADE));
|
||||
|
||||
if (file->size >= sizeof(UPGRADE))
|
||||
{
|
||||
FileRead(file, sector_buffer);
|
||||
crc = ~CalculateCRC32(-1, sector_buffer, sizeof(UPGRADE) - 4);
|
||||
printf("Upgrade ROM size : %lu\r", pUpgrade->rom.size);
|
||||
printf("Upgrade header CRC : %08lX\r", pUpgrade->crc);
|
||||
printf("Calculated header CRC : %08lX\r", crc);
|
||||
if (pUpgrade->crc == crc)
|
||||
{
|
||||
if (strncmp((const char*)pUpgrade->id, "MNMGUPG", 7) == 0 && pUpgrade->id[7] == 0)
|
||||
{
|
||||
if (pUpgrade->rom.size == file->size - sizeof(UPGRADE))
|
||||
{
|
||||
rom_size = pUpgrade->rom.size;
|
||||
rom_crc = pUpgrade->rom.crc;
|
||||
|
||||
crc = -1; // initial CRC32 value
|
||||
size = rom_size;
|
||||
while (size)
|
||||
{
|
||||
if (size > 512)
|
||||
read_size = 512;
|
||||
else
|
||||
read_size = size;
|
||||
|
||||
FileNextSector(file);
|
||||
FileRead(file, sector_buffer);
|
||||
crc = CalculateCRC32(crc, sector_buffer, read_size);
|
||||
size -= read_size;
|
||||
}
|
||||
printf("Calculated ROM CRC : %08lX\r", ~crc);
|
||||
printf("ROM CRC from header : %08lX\r", rom_crc);
|
||||
if (~crc == rom_crc)
|
||||
{ // upgrade file CRC is OK so go back to the beginning of the file
|
||||
FileSeek(file, 0, SEEK_SET);
|
||||
Error = ERROR_NONE;
|
||||
return 1;
|
||||
}
|
||||
else printf("ROM CRC mismatch! from header: %08lX, calculated: %08lX\r", rom_crc, ~crc);
|
||||
}
|
||||
else printf("ROM size mismatch! from header: %lu, from file: %lu\r", pUpgrade->rom.size, file->size-sizeof(UPGRADE));
|
||||
}
|
||||
else printf("Invalid upgrade file header!\r");
|
||||
}
|
||||
else printf("Header CRC mismatch! from header: %08lX, calculated: %08lX\r", pUpgrade->crc, crc);
|
||||
}
|
||||
else printf("Upgrade file size too small: %lu\r", file->size);
|
||||
}
|
||||
else printf("Cannot open firmware file!\r");
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *GetFirmwareVersion(fileTYPE *file, char *name) {
|
||||
static char v[16];
|
||||
|
||||
if ((!FileOpen(file, name) || file->size < sizeof(UPGRADE)))
|
||||
return NULL;
|
||||
|
||||
FileRead(file, sector_buffer);
|
||||
strncpy(v, ((UPGRADE*)sector_buffer)->version, 16);
|
||||
v[15] = 0;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
#pragma section_code_init
|
||||
RAMFUNC __noinline unsigned long WriteFirmware(fileTYPE *file)
|
||||
{
|
||||
unsigned long read_size;
|
||||
unsigned long i;
|
||||
unsigned long k;
|
||||
unsigned long page;
|
||||
unsigned long *pSrc;
|
||||
unsigned long *pDst;
|
||||
unsigned long size;
|
||||
|
||||
size = file->size - sizeof(UPGRADE);
|
||||
page = 0;
|
||||
pDst = 0;
|
||||
|
||||
*AT91C_MC_FMR = 48 << 16 | FWS << 8; // MCLK cycles in 1us
|
||||
for (i = 0; i < 16; i++)
|
||||
if (*AT91C_MC_FSR & 1 << 16 + i)
|
||||
{ // page is locked
|
||||
while (!(*AT91C_MC_FSR & AT91C_MC_FRDY)); // wait for ready
|
||||
*AT91C_MC_FCR = 0x5A << 24 | i << 6 + 8 | AT91C_MC_FCMD_UNLOCK; // unlock page
|
||||
while (!(*AT91C_MC_FSR & AT91C_MC_FRDY)); // wait for ready
|
||||
}
|
||||
|
||||
*AT91C_MC_FMR = 72 << 16 | FWS << 8; // MCLK cycles in 1.5us
|
||||
|
||||
while (size)
|
||||
{
|
||||
if (size > 512)
|
||||
read_size = 512;
|
||||
else
|
||||
read_size = size;
|
||||
|
||||
FileNextSector(file);
|
||||
FileRead(file, sector_buffer);
|
||||
|
||||
// fill the rest of buffer
|
||||
for (i = read_size; i < 512; i++)
|
||||
sector_buffer[i] = 0xFF;
|
||||
|
||||
// programming time: 13.2 ms per disk sector (512B)
|
||||
pSrc = (unsigned long*)sector_buffer;
|
||||
k = 2;
|
||||
while (k--)
|
||||
{
|
||||
i = 256 / 4;
|
||||
while (i--)
|
||||
*pDst++ = *pSrc++;
|
||||
|
||||
DISKLED_ON;
|
||||
while (!(*AT91C_MC_FSR & AT91C_MC_FRDY)); // wait for ready
|
||||
*AT91C_MC_FCR = 0x5A << 24 | page << 8 | AT91C_MC_FCMD_START_PROG; // key: 0x5A
|
||||
while (!(*AT91C_MC_FSR & AT91C_MC_FRDY)); // wait for ready
|
||||
DISKLED_OFF;
|
||||
|
||||
page++;
|
||||
}
|
||||
|
||||
size -= read_size;
|
||||
}
|
||||
*AT91C_RSTC_RCR = 0xA5 << 24 | AT91C_RSTC_PERRST | AT91C_RSTC_PROCRST; // restart
|
||||
return 0;
|
||||
}
|
||||
#pragma section_no_code_init
|
||||
|
||||
24
firmware.h
Normal file
24
firmware.h
Normal file
@@ -0,0 +1,24 @@
|
||||
typedef struct
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long base;
|
||||
unsigned long size;
|
||||
unsigned long crc;
|
||||
} romTYPE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char id[8];
|
||||
unsigned char version[16];
|
||||
romTYPE rom;
|
||||
unsigned long padding[117];
|
||||
unsigned long crc;
|
||||
} UPGRADE;
|
||||
|
||||
#define true -1
|
||||
#define false 0
|
||||
|
||||
unsigned long CalculateCRC32(unsigned long crc, unsigned char *pBuffer, unsigned long nSize);
|
||||
unsigned char CheckFirmware(fileTYPE *file, char *name);
|
||||
unsigned long WriteFirmware(fileTYPE *file) RAMFUNC;
|
||||
char *GetFirmwareVersion(fileTYPE *file, char *name);
|
||||
16
flash_sam_i_am
Normal file
16
flash_sam_i_am
Normal file
@@ -0,0 +1,16 @@
|
||||
open /dev/ttyACM0
|
||||
version
|
||||
info flash
|
||||
set
|
||||
set ramwriteallow 0x200000 0x10000
|
||||
set flashwriteallow 0x100000 0x40000
|
||||
set ramwriteallow FFFFFF64 4
|
||||
set
|
||||
writew FFFFFF64 5A000004
|
||||
shell sleep 0.1
|
||||
writew FFFFFF64 5A004004
|
||||
shell sleep 0.1
|
||||
info flash
|
||||
flash firmware.hex
|
||||
go
|
||||
exit
|
||||
775
fpga.c
Normal file
775
fpga.c
Normal file
@@ -0,0 +1,775 @@
|
||||
/*
|
||||
Copyright 2005, 2006, 2007 Dennis van Weeren
|
||||
Copyright 2008, 2009 Jakub Bednarski
|
||||
|
||||
This file is part of Minimig
|
||||
|
||||
Minimig is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Minimig is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// 2009-10-10 - any length (any multiple of 8 bytes) fpga core file support
|
||||
// 2009-12-10 - changed command header id
|
||||
// 2010-04-14 - changed command header id
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include "AT91SAM7S256.h"
|
||||
#endif
|
||||
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
#include "errors.h"
|
||||
#include "hardware.h"
|
||||
#include "fat.h"
|
||||
#include "fdd.h"
|
||||
#include "rafile.h"
|
||||
|
||||
#include "fpga.h"
|
||||
|
||||
#define CMD_HDRID 0xAACA
|
||||
|
||||
extern fileTYPE file;
|
||||
extern char s[40];
|
||||
|
||||
char BootPrint(const char *text);
|
||||
|
||||
#ifdef XILINX_CCLK
|
||||
|
||||
// single byte serialization of FPGA configuration datastream
|
||||
void ShiftFpga(unsigned char data)
|
||||
{
|
||||
AT91_REG *ppioa_codr = AT91C_PIOA_CODR;
|
||||
AT91_REG *ppioa_sodr = AT91C_PIOA_SODR;
|
||||
|
||||
// bit 0
|
||||
*ppioa_codr = XILINX_DIN | XILINX_CCLK;
|
||||
if (data & 0x80)
|
||||
*ppioa_sodr = XILINX_DIN;
|
||||
*ppioa_sodr = XILINX_CCLK;
|
||||
|
||||
// bit 1
|
||||
*ppioa_codr = XILINX_DIN | XILINX_CCLK;
|
||||
if (data & 0x40)
|
||||
*ppioa_sodr = XILINX_DIN;
|
||||
*ppioa_sodr = XILINX_CCLK;
|
||||
|
||||
// bit 2
|
||||
*ppioa_codr = XILINX_DIN | XILINX_CCLK;
|
||||
if (data & 0x20)
|
||||
*ppioa_sodr = XILINX_DIN;
|
||||
*ppioa_sodr = XILINX_CCLK;
|
||||
|
||||
// bit 3
|
||||
*ppioa_codr = XILINX_DIN | XILINX_CCLK;
|
||||
if (data & 0x10)
|
||||
*ppioa_sodr = XILINX_DIN;
|
||||
*ppioa_sodr = XILINX_CCLK;
|
||||
|
||||
// bit 4
|
||||
*ppioa_codr = XILINX_DIN | XILINX_CCLK;
|
||||
if (data & 0x08)
|
||||
*ppioa_sodr = XILINX_DIN;
|
||||
*ppioa_sodr = XILINX_CCLK;
|
||||
|
||||
// bit 5
|
||||
*ppioa_codr = XILINX_DIN | XILINX_CCLK;
|
||||
if (data & 0x04)
|
||||
*ppioa_sodr = XILINX_DIN;
|
||||
*ppioa_sodr = XILINX_CCLK;
|
||||
|
||||
// bit 6
|
||||
*ppioa_codr = XILINX_DIN | XILINX_CCLK;
|
||||
if (data & 0x02)
|
||||
*ppioa_sodr = XILINX_DIN;
|
||||
*ppioa_sodr = XILINX_CCLK;
|
||||
|
||||
// bit 7
|
||||
*ppioa_codr = XILINX_DIN | XILINX_CCLK;
|
||||
if (data & 0x01)
|
||||
*ppioa_sodr = XILINX_DIN;
|
||||
*ppioa_sodr = XILINX_CCLK;
|
||||
|
||||
}
|
||||
|
||||
// Xilinx FPGA configuration
|
||||
unsigned char ConfigureFpga(void)
|
||||
{
|
||||
unsigned long t;
|
||||
unsigned long n;
|
||||
unsigned char *ptr;
|
||||
|
||||
// set outputs
|
||||
*AT91C_PIOA_SODR = XILINX_CCLK | XILINX_DIN | XILINX_PROG_B;
|
||||
// enable outputs
|
||||
*AT91C_PIOA_OER = XILINX_CCLK | XILINX_DIN | XILINX_PROG_B;
|
||||
|
||||
// reset FGPA configuration sequence
|
||||
// specs: PROG_B pulse min 0.3 us
|
||||
t = 15;
|
||||
while (--t)
|
||||
*AT91C_PIOA_CODR = XILINX_PROG_B;
|
||||
|
||||
*AT91C_PIOA_SODR = XILINX_PROG_B;
|
||||
|
||||
// now wait for INIT to go high
|
||||
// specs: max 2ms
|
||||
t = 100000;
|
||||
while (!(*AT91C_PIOA_PDSR & XILINX_INIT_B))
|
||||
{
|
||||
if (--t == 0)
|
||||
{
|
||||
printf("FPGA init is NOT high!\r");
|
||||
FatalError(3);
|
||||
}
|
||||
}
|
||||
|
||||
printf("FPGA init is high\r");
|
||||
|
||||
if (*AT91C_PIOA_PDSR & XILINX_DONE)
|
||||
{
|
||||
printf("FPGA done is high before configuration!\r");
|
||||
FatalError(3);
|
||||
}
|
||||
|
||||
// open bitstream file
|
||||
if (FileOpen(&file, "MINIMIG1BIN") == 0)
|
||||
{
|
||||
printf("No FPGA configuration file found!\r");
|
||||
FatalError(4);
|
||||
}
|
||||
|
||||
printf("FPGA bitstream file opened\r");
|
||||
printf("[");
|
||||
|
||||
// send all bytes to FPGA in loop
|
||||
t = 0;
|
||||
n = file.size >> 3;
|
||||
ptr = sector_buffer;
|
||||
do
|
||||
{
|
||||
// read sector if 512 (64*8) bytes done
|
||||
if ((t & 0x3F) == 0)
|
||||
{
|
||||
if (t & (1<<10))
|
||||
DISKLED_OFF
|
||||
else
|
||||
DISKLED_ON
|
||||
|
||||
if ((t & 0x1FF) == 0)
|
||||
printf("*");
|
||||
|
||||
if (!FileRead(&file, sector_buffer))
|
||||
return(0);
|
||||
|
||||
ptr = sector_buffer;
|
||||
}
|
||||
|
||||
// send data in packets of 8 bytes
|
||||
ShiftFpga(*ptr++);
|
||||
ShiftFpga(*ptr++);
|
||||
ShiftFpga(*ptr++);
|
||||
ShiftFpga(*ptr++);
|
||||
ShiftFpga(*ptr++);
|
||||
ShiftFpga(*ptr++);
|
||||
ShiftFpga(*ptr++);
|
||||
ShiftFpga(*ptr++);
|
||||
|
||||
t++;
|
||||
|
||||
// read next sector if 512 (64*8) bytes done
|
||||
if ((t & 0x3F) == 0)
|
||||
FileNextSector(&file);
|
||||
|
||||
}
|
||||
while (t < n);
|
||||
|
||||
// disable outputs
|
||||
*AT91C_PIOA_ODR = XILINX_CCLK | XILINX_DIN | XILINX_PROG_B;
|
||||
|
||||
printf("]\r");
|
||||
printf("FPGA bitstream loaded\r");
|
||||
DISKLED_OFF;
|
||||
|
||||
// check if DONE is high
|
||||
if (*AT91C_PIOA_PDSR & XILINX_DONE)
|
||||
return(1);
|
||||
|
||||
printf("FPGA done is NOT high!\r");
|
||||
FatalError(5);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ALTERA_DCLK
|
||||
static inline void ShiftFpga(unsigned char data)
|
||||
{
|
||||
unsigned char i;
|
||||
for ( i = 0; i < 8; i++ )
|
||||
{
|
||||
/* Dump to DATA0 and insert a positive edge pulse at the same time */
|
||||
*AT91C_PIOA_CODR = ALTERA_DATA0 | ALTERA_DCLK;
|
||||
if((data >> i) & 1) *AT91C_PIOA_SODR = ALTERA_DATA0;
|
||||
*AT91C_PIOA_SODR = ALTERA_DCLK;
|
||||
}
|
||||
}
|
||||
|
||||
// Altera FPGA configuration
|
||||
RAMFUNC unsigned char ConfigureFpga(void)
|
||||
{
|
||||
unsigned long i;
|
||||
unsigned char *ptr;
|
||||
|
||||
// set outputs
|
||||
*AT91C_PIOA_SODR = ALTERA_DCLK | ALTERA_DATA0 | ALTERA_NCONFIG;
|
||||
// enable outputs
|
||||
*AT91C_PIOA_OER = ALTERA_DCLK | ALTERA_DATA0 | ALTERA_NCONFIG;
|
||||
|
||||
// open bitstream file
|
||||
if (FileOpen(&file, "CORE RBF") == 0)
|
||||
{
|
||||
printf("No FPGA configuration file found!\r");
|
||||
FatalError(4);
|
||||
}
|
||||
|
||||
printf("FPGA bitstream file opened, file size = %d\r", file.size);
|
||||
printf("[");
|
||||
|
||||
// send all bytes to FPGA in loop
|
||||
ptr = sector_buffer;
|
||||
|
||||
/* Drive a transition of 0 to 1 to NCONFIG to indicate start of configuration */
|
||||
*AT91C_PIOA_CODR = ALTERA_NCONFIG;
|
||||
*AT91C_PIOA_CODR = ALTERA_NCONFIG; // must be low for at least 500ns
|
||||
*AT91C_PIOA_SODR = ALTERA_NCONFIG;
|
||||
|
||||
// now wait for NSTATUS to go high
|
||||
// specs: max 800us
|
||||
i = 100000;
|
||||
while (!(*AT91C_PIOA_PDSR & ALTERA_NSTATUS))
|
||||
{
|
||||
if (--i == 0)
|
||||
{
|
||||
printf("FPGA NSTATUS is NOT high!\r");
|
||||
FatalError(3);
|
||||
}
|
||||
}
|
||||
|
||||
DISKLED_ON;
|
||||
|
||||
int t = 0;
|
||||
int n = file.size >> 3;
|
||||
|
||||
/* Loop through every single byte */
|
||||
for ( i = 0; i < file.size; )
|
||||
{
|
||||
// read sector if 512 (64*8) bytes done
|
||||
if ((i & 0x1FF) == 0)
|
||||
{
|
||||
if (i & (1<<13))
|
||||
DISKLED_OFF
|
||||
else
|
||||
DISKLED_ON
|
||||
|
||||
if ((i & 0x3FFF) == 0)
|
||||
printf("*");
|
||||
|
||||
if (!FileRead(&file, sector_buffer))
|
||||
return(0);
|
||||
|
||||
ptr = sector_buffer;
|
||||
}
|
||||
|
||||
int bytes2copy = (i < file.size - 8)?8:file.size-i;
|
||||
i += bytes2copy;
|
||||
while(bytes2copy) {
|
||||
ShiftFpga(*ptr++);
|
||||
bytes2copy--;
|
||||
}
|
||||
|
||||
/* Check for error through NSTATUS for every 10KB programmed and the last byte */
|
||||
if ( !(i % 10240) || (i == file.size - 1) ) {
|
||||
if ( !*AT91C_PIOA_PDSR & ALTERA_NSTATUS ) {
|
||||
printf("FPGA NSTATUS is NOT high!\r");
|
||||
FatalError(5);
|
||||
}
|
||||
}
|
||||
|
||||
// read next sector if 512 (64*8) bytes done
|
||||
if ((i & 0x1FF) == 0)
|
||||
FileNextSector(&file);
|
||||
}
|
||||
|
||||
printf("]\r");
|
||||
printf("FPGA bitstream loaded\r");
|
||||
DISKLED_OFF;
|
||||
|
||||
// check if DONE is high
|
||||
if (!(*AT91C_PIOA_PDSR & ALTERA_DONE)) {
|
||||
printf("FPGA Configuration done but contains error... CONF_DONE is LOW\r");
|
||||
FatalError(5);
|
||||
}
|
||||
|
||||
|
||||
/* Start initialization */
|
||||
/* Clock another extra DCLK cycles while initialization is in progress
|
||||
through internal oscillator or driving clock cycles into CLKUSR pin */
|
||||
/* These extra DCLK cycles do not initialize the device into USER MODE */
|
||||
/* It is not required to drive extra DCLK cycles at the end of configuration */
|
||||
/* The purpose of driving extra DCLK cycles here is to insert some delay
|
||||
while waiting for the initialization of the device to complete before
|
||||
checking the CONFDONE and NSTATUS signals at the end of whole
|
||||
configuration cycle */
|
||||
|
||||
for ( i = 0; i < 50; i++ )
|
||||
{
|
||||
*AT91C_PIOA_CODR = ALTERA_DCLK;
|
||||
*AT91C_PIOA_SODR = ALTERA_DCLK;
|
||||
}
|
||||
|
||||
/* Initialization end */
|
||||
|
||||
if ( !(*AT91C_PIOA_PDSR & ALTERA_NSTATUS) ||
|
||||
!(*AT91C_PIOA_PDSR & ALTERA_DONE)) {
|
||||
|
||||
printf("FPGA Initialization finish but contains error: NSTATUS is %s and CONF_DONE is %s.\r",
|
||||
((*AT91C_PIOA_PDSR & ALTERA_NSTATUS)?"HIGH":"LOW"), ((*AT91C_PIOA_PDSR & ALTERA_DONE)?"HIGH":"LOW") );
|
||||
FatalError(5);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void SendFile(RAFile *file)
|
||||
{
|
||||
unsigned char c1, c2;
|
||||
unsigned long j;
|
||||
unsigned long n;
|
||||
unsigned char *p;
|
||||
|
||||
printf("[");
|
||||
n = (file->file.size + 511) >> 9; // sector count (rounded up)
|
||||
while (n--)
|
||||
{
|
||||
// read data sector from memory card
|
||||
RARead(file,sector_buffer,512);
|
||||
|
||||
do
|
||||
{
|
||||
// read FPGA status
|
||||
EnableFpga();
|
||||
c1 = SPI(0);
|
||||
c2 = SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
DisableFpga();
|
||||
}
|
||||
while (!(c1 & CMD_RDTRK));
|
||||
|
||||
if ((n & 15) == 0)
|
||||
printf("*");
|
||||
|
||||
// send data sector to FPGA
|
||||
EnableFpga();
|
||||
c1 = SPI(0);
|
||||
c2 = SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
p = sector_buffer;
|
||||
|
||||
for (j = 0; j < 512; j++)
|
||||
SPI(*p++);
|
||||
|
||||
DisableFpga();
|
||||
}
|
||||
printf("]\r");
|
||||
}
|
||||
|
||||
|
||||
void SendFileEncrypted(RAFile *file,unsigned char *key,int keysize)
|
||||
{
|
||||
unsigned char c1, c2;
|
||||
unsigned char headersize;
|
||||
unsigned int keyidx=0;
|
||||
unsigned long j;
|
||||
unsigned long n;
|
||||
unsigned char *p;
|
||||
int badbyte=0;
|
||||
|
||||
printf("[");
|
||||
headersize=file->size&255; // ROM should be a round number of kilobytes; overspill will likely be the Amiga Forever header.
|
||||
|
||||
RARead(file,sector_buffer,headersize); // Read extra bytes
|
||||
|
||||
n = (file->size + (511-headersize)) >> 9; // sector count (rounded up)
|
||||
while (n--)
|
||||
{
|
||||
RARead(file,sector_buffer,512);
|
||||
for (j = 0; j < 512; j++)
|
||||
{
|
||||
sector_buffer[j]^=key[keyidx++];
|
||||
if(keyidx>=keysize)
|
||||
keyidx-=keysize;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
// read FPGA status
|
||||
EnableFpga();
|
||||
c1 = SPI(0);
|
||||
c2 = SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
DisableFpga();
|
||||
}
|
||||
while (!(c1 & CMD_RDTRK));
|
||||
|
||||
if ((n & 15) == 0)
|
||||
printf("*");
|
||||
|
||||
// send data sector to FPGA
|
||||
EnableFpga();
|
||||
c1 = SPI(0);
|
||||
c2 = SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
p = sector_buffer;
|
||||
|
||||
for (j = 0; j < 512; j++)
|
||||
SPI(*p++);
|
||||
DisableFpga();
|
||||
}
|
||||
printf("]\r");
|
||||
}
|
||||
|
||||
|
||||
// draw on screen
|
||||
char BootDraw(char *data, unsigned short len, unsigned short offset)
|
||||
{
|
||||
DEBUG_FUNC_IN();
|
||||
|
||||
unsigned char c1, c2, c3, c4;
|
||||
unsigned char cmd;
|
||||
const char *p;
|
||||
unsigned short n;
|
||||
unsigned short i;
|
||||
|
||||
n = (len+3)&(~3);
|
||||
i = 0;
|
||||
|
||||
cmd = 1;
|
||||
while (1)
|
||||
{
|
||||
EnableFpga();
|
||||
c1 = SPI(0x10); // track read command
|
||||
c2 = SPI(0x01); // disk present
|
||||
unsigned char x = SPI(0);
|
||||
unsigned char y = SPI(0);
|
||||
c3 = SPI(0);
|
||||
c4 = SPI(0);
|
||||
|
||||
// printf("FPGA state: %d %d (%d %d) %d %d\n", c1, c2, x, y, c3, c4);
|
||||
|
||||
if (c1 & CMD_RDTRK)
|
||||
{
|
||||
if (cmd)
|
||||
{ // command phase
|
||||
if (c3 == 0x80 && c4 == 0x06) // command packet size must be 12 bytes
|
||||
{
|
||||
cmd = 0;
|
||||
SPI(CMD_HDRID >> 8); // command header
|
||||
SPI(CMD_HDRID & 0xFF);
|
||||
SPI(0x00); // cmd: 0x0001 = print text
|
||||
SPI(0x01);
|
||||
// data packet size in bytes
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI((n)>>8);
|
||||
SPI((n)&0xff); // +2 because only even byte count is possible to send and we have to send termination zero byte
|
||||
// offset
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(offset>>8);
|
||||
SPI(offset&0xff);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
else
|
||||
{ // data phase
|
||||
if (c3 == 0x80 && c4 == ((n) >> 1))
|
||||
{
|
||||
p = data;
|
||||
n = c4 << 1;
|
||||
while (n--)
|
||||
{
|
||||
c4 = *p;
|
||||
SPI((i>=len) ? 0 : c4);
|
||||
p++;
|
||||
i++;
|
||||
}
|
||||
DisableFpga();
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
DisableFpga();
|
||||
}
|
||||
DisableFpga();
|
||||
return 0;
|
||||
|
||||
DEBUG_FUNC_OUT();
|
||||
}
|
||||
|
||||
|
||||
// print message on the boot screen
|
||||
char BootPrint(const char *text)
|
||||
{
|
||||
unsigned char c1, c2, c3, c4;
|
||||
unsigned char cmd;
|
||||
const char *p;
|
||||
unsigned char n;
|
||||
|
||||
return 0;
|
||||
|
||||
p = text;
|
||||
n = 0;
|
||||
while (*p++ != 0)
|
||||
n++; // calculating string length
|
||||
|
||||
cmd = 1;
|
||||
while (1)
|
||||
{
|
||||
EnableFpga();
|
||||
c1 = SPI(0x10); // track read command
|
||||
c2 = SPI(0x01); // disk present
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
c3 = SPI(0);
|
||||
c4 = SPI(0);
|
||||
|
||||
if (c1 & CMD_RDTRK)
|
||||
{
|
||||
if (cmd)
|
||||
{ // command phase
|
||||
if (c3 == 0x80 && c4 == 0x06) // command packet size must be 12 bytes
|
||||
{
|
||||
cmd = 0;
|
||||
SPI(CMD_HDRID >> 8); // command header
|
||||
SPI(CMD_HDRID & 0xFF);
|
||||
SPI(0x00); // cmd: 0x0001 = print text
|
||||
SPI(0x01);
|
||||
// data packet size in bytes
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(n+2); // +2 because only even byte count is possible to send and we have to send termination zero byte
|
||||
// don't care
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
else
|
||||
{ // data phase
|
||||
if (c3 == 0x80 && c4 == ((n + 2) >> 1))
|
||||
{
|
||||
p = text;
|
||||
n = c4 << 1;
|
||||
while (n--)
|
||||
{
|
||||
c4 = *p;
|
||||
SPI(c4);
|
||||
if (c4) // if current character is not zero go to next one
|
||||
p++;
|
||||
}
|
||||
DisableFpga();
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
DisableFpga();
|
||||
}
|
||||
DisableFpga();
|
||||
return 0;
|
||||
}
|
||||
|
||||
char PrepareBootUpload(unsigned char base, unsigned char size)
|
||||
// this function sends given file to Minimig's memory
|
||||
// base - memory base address (bits 23..16)
|
||||
// size - memory size (bits 23..16)
|
||||
{
|
||||
unsigned char c1, c2, c3, c4;
|
||||
unsigned char cmd = 1;
|
||||
|
||||
while (1)
|
||||
{
|
||||
EnableFpga();
|
||||
c1 = SPI(0x10); // track read command
|
||||
c2 = SPI(0x01); // disk present
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
c3 = SPI(0);
|
||||
c4 = SPI(0);
|
||||
|
||||
if (c1 & CMD_RDTRK)
|
||||
{
|
||||
if (cmd)
|
||||
{ // command phase
|
||||
if (c3 == 0x80 && c4 == 0x06) // command packet size 12 bytes
|
||||
{
|
||||
cmd = 0;
|
||||
SPI(CMD_HDRID >> 8); // command header
|
||||
SPI(CMD_HDRID & 0xFF);
|
||||
SPI(0x00);
|
||||
SPI(0x02); // cmd: 0x0002 = upload memory
|
||||
// memory base address
|
||||
SPI(0x00);
|
||||
SPI(base);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
// memory size
|
||||
SPI(0x00);
|
||||
SPI(size);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
else
|
||||
{ // data phase
|
||||
DisableFpga();
|
||||
printf("Ready to upload ROM file...\r");
|
||||
// send rom image to FPGA
|
||||
// SendFile(file);
|
||||
// printf("ROM file uploaded.\r");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
DisableFpga();
|
||||
}
|
||||
DisableFpga();
|
||||
return -1;
|
||||
}
|
||||
|
||||
void BootExit(void)
|
||||
{
|
||||
unsigned char c1, c2, c3, c4;
|
||||
|
||||
while (1)
|
||||
{
|
||||
EnableFpga();
|
||||
c1 = SPI(0x10); // track read command
|
||||
c2 = SPI(0x01); // disk present
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
c3 = SPI(0);
|
||||
c4 = SPI(0);
|
||||
if (c1 & CMD_RDTRK)
|
||||
{
|
||||
if (c3 == 0x80 && c4 == 0x06) // command packet size 12 bytes
|
||||
{
|
||||
SPI(CMD_HDRID >> 8); // command header
|
||||
SPI(CMD_HDRID & 0xFF);
|
||||
SPI(0x00); // cmd: 0x0003 = restart
|
||||
SPI(0x03);
|
||||
// don't care
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
// don't care
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
}
|
||||
DisableFpga();
|
||||
return;
|
||||
}
|
||||
DisableFpga();
|
||||
}
|
||||
}
|
||||
|
||||
void ClearMemory(unsigned long base, unsigned long size)
|
||||
{
|
||||
unsigned char c1, c2, c3, c4;
|
||||
|
||||
while (1)
|
||||
{
|
||||
EnableFpga();
|
||||
c1 = SPI(0x10); // track read command
|
||||
c2 = SPI(0x01); // disk present
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
c3 = SPI(0);
|
||||
c4 = SPI(0);
|
||||
if (c1 & CMD_RDTRK)
|
||||
{
|
||||
if (c3 == 0x80 && c4 == 0x06)// command packet size 12 bytes
|
||||
{
|
||||
SPI(CMD_HDRID >> 8); // command header
|
||||
SPI(CMD_HDRID & 0xFF);
|
||||
SPI(0x00); // cmd: 0x0004 = clear memory
|
||||
SPI(0x04);
|
||||
// memory base
|
||||
SPI((unsigned char)(base >> 24));
|
||||
SPI((unsigned char)(base >> 16));
|
||||
SPI((unsigned char)(base >> 8));
|
||||
SPI((unsigned char)base);
|
||||
// memory size
|
||||
SPI((unsigned char)(size >> 24));
|
||||
SPI((unsigned char)(size >> 16));
|
||||
SPI((unsigned char)(size >> 8));
|
||||
SPI((unsigned char)size);
|
||||
}
|
||||
DisableFpga();
|
||||
return;
|
||||
}
|
||||
DisableFpga();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char GetFPGAStatus(void)
|
||||
{
|
||||
unsigned char status;
|
||||
|
||||
EnableFpga();
|
||||
status = SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
DisableFpga();
|
||||
|
||||
return status;
|
||||
}
|
||||
17
fpga.h
Normal file
17
fpga.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef FPGA_H
|
||||
#define FPGA_H
|
||||
|
||||
#include "rafile.h"
|
||||
|
||||
unsigned char ConfigureFpga(void) RAMFUNC;
|
||||
void SendFile(RAFile *file);
|
||||
void SendFileEncrypted(RAFile *file,unsigned char *key,int keysize);
|
||||
char BootDraw(char *data, unsigned short len, unsigned short offset);
|
||||
char BootPrint(const char *text);
|
||||
char PrepareBootUpload(unsigned char base, unsigned char size);
|
||||
void BootExit(void);
|
||||
void ClearMemory(unsigned long base, unsigned long size);
|
||||
unsigned char GetFPGAStatus(void);
|
||||
|
||||
#endif
|
||||
|
||||
281
hardware.c
Normal file
281
hardware.c
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
Copyright 2008, 2009 Jakub Bednarski
|
||||
|
||||
This file is part of Minimig
|
||||
|
||||
Minimig is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Minimig is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "AT91SAM7S256.h"
|
||||
#include "stdio.h"
|
||||
#include "hardware.h"
|
||||
|
||||
void __init_hardware(void)
|
||||
{
|
||||
*AT91C_WDTC_WDMR = AT91C_WDTC_WDDIS; // disable watchdog
|
||||
*AT91C_RSTC_RMR = (0xA5 << 24) | AT91C_RSTC_URSTEN; // enable external user reset input
|
||||
*AT91C_MC_FMR = FWS << 8; // Flash wait states
|
||||
|
||||
// configure clock generator
|
||||
*AT91C_CKGR_MOR = AT91C_CKGR_MOSCEN | (40 << 8);
|
||||
while (!(*AT91C_PMC_SR & AT91C_PMC_MOSCS));
|
||||
|
||||
*AT91C_CKGR_PLLR = AT91C_CKGR_OUT_0 | AT91C_CKGR_USBDIV_1 | (25 << 16) | (40 << 8) | 5; // DIV=5 MUL=26 USBDIV=1 (2) PLLCOUNT=40
|
||||
while (!(*AT91C_PMC_SR & AT91C_PMC_LOCK));
|
||||
|
||||
*AT91C_PMC_MCKR = AT91C_PMC_PRES_CLK_2; // master clock register: clock source selection
|
||||
while (!(*AT91C_PMC_SR & AT91C_PMC_MCKRDY));
|
||||
|
||||
*AT91C_PMC_MCKR = AT91C_PMC_CSS_PLL_CLK | AT91C_PMC_PRES_CLK_2; // master clock register: clock source selection
|
||||
while (!(*AT91C_PMC_SR & AT91C_PMC_MCKRDY));
|
||||
|
||||
*AT91C_PIOA_PER = 0xFFFFFFFF; // enable pio on all pins
|
||||
*AT91C_PIOA_SODR = DISKLED; // led off
|
||||
|
||||
#ifdef USB_PUP
|
||||
// disable usb d+/d- pullups if present
|
||||
*AT91C_PIOA_OER = USB_PUP;
|
||||
*AT91C_PIOA_PPUDR = USB_PUP;
|
||||
*AT91C_PIOA_SODR = USB_PUP;
|
||||
#endif
|
||||
|
||||
// enable joystick ports
|
||||
#ifdef JOY0
|
||||
*AT91C_PIOA_PPUER = JOY0;
|
||||
#endif
|
||||
|
||||
#ifdef JOY1
|
||||
*AT91C_PIOA_PPUER = JOY1;
|
||||
#endif
|
||||
|
||||
*AT91C_PIOA_SODR = MMC_SEL | FPGA0 | FPGA1 | FPGA2; // set output data register
|
||||
|
||||
// output enable register
|
||||
*AT91C_PIOA_OER = DISKLED | MMC_SEL | FPGA0 | FPGA1 | FPGA2;
|
||||
// pull-up disable register
|
||||
*AT91C_PIOA_PPUDR = DISKLED | MMC_SEL | FPGA0 | FPGA1 | FPGA2;
|
||||
|
||||
#ifdef XILINX_CCLK
|
||||
// xilinx interface
|
||||
*AT91C_PIOA_SODR = XILINX_CCLK | XILINX_DIN | XILINX_PROG_B;
|
||||
*AT91C_PIOA_OER = XILINX_CCLK | XILINX_DIN | XILINX_PROG_B;
|
||||
*AT91C_PIOA_PPUDR = XILINX_CCLK | XILINX_DIN | XILINX_PROG_B |
|
||||
XILINX_INIT_B | XILINX_DONE;
|
||||
#endif
|
||||
|
||||
#ifdef ALTERA_DCLK
|
||||
// altera interface
|
||||
*AT91C_PIOA_SODR = ALTERA_DCLK | ALTERA_DATA0 | ALTERA_NCONFIG;
|
||||
*AT91C_PIOA_OER = ALTERA_DCLK | ALTERA_DATA0 | ALTERA_NCONFIG;
|
||||
*AT91C_PIOA_PPUDR = ALTERA_DCLK | ALTERA_DATA0 | ALTERA_NCONFIG |
|
||||
ALTERA_NSTATUS | ALTERA_DONE;
|
||||
#endif
|
||||
|
||||
#ifdef MMC_CLKEN
|
||||
// MMC_CLKEN may be present
|
||||
// (but is not used anymore, so it's only setup passive)
|
||||
*AT91C_PIOA_SODR = MMC_CLKEN;
|
||||
*AT91C_PIOA_PPUDR = MMC_CLKEN;
|
||||
#endif
|
||||
|
||||
#ifdef USB_SEL
|
||||
*AT91C_PIOA_SODR = USB_SEL;
|
||||
*AT91C_PIOA_OER = USB_SEL;
|
||||
*AT91C_PIOA_PPUDR = USB_SEL;
|
||||
#endif
|
||||
|
||||
// Enable peripheral clock in the PMC
|
||||
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOA;
|
||||
}
|
||||
|
||||
void USART_Init(unsigned long baudrate)
|
||||
{
|
||||
// Configure PA5 and PA6 for USART0 use
|
||||
AT91C_BASE_PIOA->PIO_PDR = AT91C_PA5_RXD0 | AT91C_PA6_TXD0;
|
||||
|
||||
// Enable the peripheral clock in the PMC
|
||||
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_US0;
|
||||
|
||||
// Reset and disable receiver & transmitter
|
||||
AT91C_BASE_US0->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX | AT91C_US_RXDIS | AT91C_US_TXDIS;
|
||||
|
||||
// Configure USART0 mode
|
||||
AT91C_BASE_US0->US_MR = AT91C_US_USMODE_NORMAL | AT91C_US_CLKS_CLOCK | AT91C_US_CHRL_8_BITS | AT91C_US_PAR_NONE | AT91C_US_NBSTOP_1_BIT | AT91C_US_CHMODE_NORMAL;
|
||||
|
||||
// Configure USART0 rate
|
||||
AT91C_BASE_US0->US_BRGR = MCLK / 16 / baudrate;
|
||||
|
||||
// Enable receiver & transmitter
|
||||
AT91C_BASE_US0->US_CR = AT91C_US_RXEN | AT91C_US_TXEN;
|
||||
}
|
||||
|
||||
RAMFUNC void USART_Write(unsigned char c)
|
||||
{
|
||||
while (!(AT91C_BASE_US0->US_CSR & AT91C_US_TXEMPTY));
|
||||
AT91C_BASE_US0->US_THR = c;
|
||||
}
|
||||
|
||||
#ifndef __GNUC__
|
||||
signed int fputc(signed int c, FILE *pStream)
|
||||
{
|
||||
if ((pStream == stdout) || (pStream == stderr))
|
||||
{
|
||||
USART_Write((unsigned char)c);
|
||||
return c;
|
||||
}
|
||||
|
||||
return EOF;
|
||||
}
|
||||
#endif
|
||||
|
||||
void SPI_Init()
|
||||
{
|
||||
// Enable the peripheral clock in the PMC
|
||||
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_SPI;
|
||||
|
||||
// Enable SPI interface
|
||||
*AT91C_SPI_CR = AT91C_SPI_SPIEN;
|
||||
|
||||
// SPI Mode Register
|
||||
*AT91C_SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | (0x0E << 16);
|
||||
|
||||
// SPI CS register
|
||||
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (48 << 8) | (0x00 << 16) | (0x01 << 24);
|
||||
|
||||
// Configure pins for SPI use
|
||||
AT91C_BASE_PIOA->PIO_PDR = AT91C_PA14_SPCK | AT91C_PA13_MOSI | AT91C_PA12_MISO;
|
||||
}
|
||||
|
||||
void EnableFpga()
|
||||
{
|
||||
*AT91C_PIOA_CODR = FPGA0; // clear output
|
||||
}
|
||||
|
||||
void DisableFpga()
|
||||
{
|
||||
SPI_Wait4XferEnd();
|
||||
*AT91C_PIOA_SODR = FPGA0; // set output
|
||||
}
|
||||
|
||||
void EnableOsd()
|
||||
{
|
||||
*AT91C_PIOA_CODR = FPGA1; // clear output
|
||||
}
|
||||
|
||||
void DisableOsd()
|
||||
{
|
||||
SPI_Wait4XferEnd();
|
||||
*AT91C_PIOA_SODR = FPGA1; // set output
|
||||
}
|
||||
|
||||
#ifdef FPGA3
|
||||
void EnableIO() {
|
||||
*AT91C_PIOA_CODR = FPGA3; // clear output
|
||||
}
|
||||
|
||||
void DisableIO() {
|
||||
SPI_Wait4XferEnd();
|
||||
*AT91C_PIOA_SODR = FPGA3; // set output
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned long CheckButton(void)
|
||||
{
|
||||
#ifdef BUTTON
|
||||
return((~*AT91C_PIOA_PDSR) & BUTTON);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Timer_Init(void)
|
||||
{
|
||||
*AT91C_PITC_PIMR = AT91C_PITC_PITEN | ((MCLK / 16 / 1000 - 1) & AT91C_PITC_PIV); // counting period 1ms
|
||||
}
|
||||
|
||||
unsigned long GetTimer(unsigned long offset)
|
||||
{
|
||||
unsigned long systimer = (*AT91C_PITC_PIIR & AT91C_PITC_PICNT);
|
||||
systimer += offset << 20;
|
||||
return (systimer); // valid bits [31:20]
|
||||
}
|
||||
|
||||
unsigned long CheckTimer(unsigned long time)
|
||||
{
|
||||
unsigned long systimer = (*AT91C_PITC_PIIR & AT91C_PITC_PICNT);
|
||||
time -= systimer;
|
||||
return(time > (1UL << 31));
|
||||
}
|
||||
|
||||
void WaitTimer(unsigned long time)
|
||||
{
|
||||
time = GetTimer(time);
|
||||
while (!CheckTimer(time));
|
||||
}
|
||||
|
||||
void SPI_slow() {
|
||||
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (SPI_SLOW_CLK_VALUE << 8) | (2 << 24); // init clock 100-400 kHz
|
||||
}
|
||||
|
||||
void SPI_fast() {
|
||||
// set appropriate SPI speed for SD/SDHC card (max 25 Mhz)
|
||||
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (SPI_SDC_CLK_VALUE << 8); // 24 MHz SPI clock
|
||||
}
|
||||
|
||||
void SPI_fast_mmc() {
|
||||
// set appropriate SPI speed for MMC card (max 20Mhz)
|
||||
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (SPI_MMC_CLK_VALUE << 8); // 16 MHz SPI clock
|
||||
}
|
||||
|
||||
void TIMER_wait(unsigned long ms) {
|
||||
WaitTimer(ms);
|
||||
}
|
||||
|
||||
void EnableDMode() {
|
||||
*AT91C_PIOA_CODR = FPGA2; // enable FPGA2 output
|
||||
}
|
||||
|
||||
void DisableDMode() {
|
||||
*AT91C_PIOA_SODR = FPGA2; // disable FPGA2 output
|
||||
}
|
||||
|
||||
void SPI_block(unsigned short num) {
|
||||
unsigned short i;
|
||||
unsigned long t;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
while (!(*AT91C_SPI_SR & AT91C_SPI_TDRE)); // wait until transmiter buffer is empty
|
||||
*AT91C_SPI_TDR = 0xFF; // write dummy spi data
|
||||
}
|
||||
while (!(*AT91C_SPI_SR & AT91C_SPI_TXEMPTY)); // wait for transfer end
|
||||
t = *AT91C_SPI_RDR; // dummy read to empty receiver buffer for new data
|
||||
}
|
||||
|
||||
RAMFUNC void SPI_block_read(char *addr) {
|
||||
*AT91C_PIOA_SODR = AT91C_PA13_MOSI; // set GPIO output register
|
||||
*AT91C_PIOA_OER = AT91C_PA13_MOSI; // GPIO pin as output
|
||||
*AT91C_PIOA_PER = AT91C_PA13_MOSI; // enable GPIO function
|
||||
// use SPI PDC (DMA transfer)
|
||||
*AT91C_SPI_TPR = (unsigned long)addr;
|
||||
*AT91C_SPI_TCR = 512;
|
||||
*AT91C_SPI_TNCR = 0;
|
||||
*AT91C_SPI_RPR = (unsigned long)addr;
|
||||
*AT91C_SPI_RCR = 512;
|
||||
*AT91C_SPI_RNCR = 0;
|
||||
*AT91C_SPI_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN; // start DMA transfer
|
||||
// wait for tranfer end
|
||||
while ((*AT91C_SPI_SR & (AT91C_SPI_ENDTX | AT91C_SPI_ENDRX)) != (AT91C_SPI_ENDTX | AT91C_SPI_ENDRX));
|
||||
*AT91C_SPI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS; // disable transmitter and receiver
|
||||
*AT91C_PIOA_PDR = AT91C_PA13_MOSI; // disable GPIO function
|
||||
}
|
||||
152
hardware.h
Normal file
152
hardware.h
Normal file
@@ -0,0 +1,152 @@
|
||||
#include "AT91SAM7S256.h"
|
||||
|
||||
#ifndef HARDWARE_H
|
||||
#define HARDWARE_H
|
||||
|
||||
#define MCLK 48000000
|
||||
#define FWS 1 // Flash wait states
|
||||
|
||||
#define RAMFUNC __attribute__ ((long_call, section (".ramsection")))
|
||||
|
||||
#if defined(MINIMIG_V1_0)
|
||||
#define DISKLED AT91C_PIO_PA10
|
||||
#define DISKLED_ON *AT91C_PIOA_SODR = DISKLED;
|
||||
#define DISKLED_OFF *AT91C_PIOA_CODR = DISKLED;
|
||||
#define MMC_CLKEN AT91C_PIO_PA24
|
||||
#define MMC_SEL AT91C_PIO_PA27
|
||||
#define BUTTON AT91C_PIO_PA28
|
||||
|
||||
// xilinx programming interface
|
||||
#define XILINX_DIN AT91C_PIO_PA20
|
||||
#define XILINX_CCLK AT91C_PIO_PA4
|
||||
#define XILINX_PROG_B AT91C_PIO_PA9
|
||||
#define XILINX_INIT_B AT91C_PIO_PA7
|
||||
#define XILINX_DONE AT91C_PIO_PA8
|
||||
|
||||
#elif defined(SAM7_P256)
|
||||
#define DISKLED AT91C_PIO_PA18
|
||||
#define DISKLED_ON *AT91C_PIOA_CODR = DISKLED;
|
||||
#define DISKLED_OFF *AT91C_PIOA_SODR = DISKLED;
|
||||
#define MMC_SEL AT91C_PIO_PA11
|
||||
#define BUTTON AT91C_PIO_PA19
|
||||
#define USB_SEL AT91C_PIO_PA31
|
||||
#define USB_PUP (AT91C_PIO_PA16 || AT91C_PIO_PA8)
|
||||
|
||||
// altera programming interface
|
||||
#define ALTERA_DONE AT91C_PIO_PA2
|
||||
#define ALTERA_DATA0 AT91C_PIO_PA3
|
||||
#define ALTERA_NCONFIG AT91C_PIO_PA1
|
||||
#define ALTERA_NSTATUS AT91C_PIO_PA0
|
||||
#define ALTERA_DCLK AT91C_PIO_PA4
|
||||
|
||||
#elif defined(MIST)
|
||||
#define DISKLED AT91C_PIO_PA29
|
||||
#define DISKLED_ON *AT91C_PIOA_CODR = DISKLED;
|
||||
#define DISKLED_OFF *AT91C_PIOA_SODR = DISKLED;
|
||||
#define MMC_SEL AT91C_PIO_PA31
|
||||
#define USB_SEL AT91C_PIO_PA11
|
||||
#define USB_PUP AT91C_PIO_PA16
|
||||
|
||||
// altera programming interface
|
||||
#define ALTERA_DONE AT91C_PIO_PA4
|
||||
#define ALTERA_DATA0 AT91C_PIO_PA9
|
||||
#define ALTERA_NCONFIG AT91C_PIO_PA8
|
||||
#define ALTERA_NSTATUS AT91C_PIO_PA7
|
||||
#define ALTERA_DCLK AT91C_PIO_PA15
|
||||
|
||||
// db9 joystick ports
|
||||
#define JOY1_UP AT91C_PIO_PA28
|
||||
#define JOY1_DOWN AT91C_PIO_PA27
|
||||
#define JOY1_LEFT AT91C_PIO_PA26
|
||||
#define JOY1_RIGHT AT91C_PIO_PA25
|
||||
#define JOY1_BTN1 AT91C_PIO_PA24
|
||||
#define JOY1_BTN2 AT91C_PIO_PA23
|
||||
#define JOY1 (JOY1_UP|JOY1_DOWN|JOY1_LEFT|JOY1_RIGHT|JOY1_BTN1|JOY1_BTN2)
|
||||
|
||||
#define JOY0_UP AT91C_PIO_PA22
|
||||
#define JOY0_DOWN AT91C_PIO_PA21
|
||||
#define JOY0_LEFT AT91C_PIO_PA20
|
||||
#define JOY0_RIGHT AT91C_PIO_PA19
|
||||
#define JOY0_BTN1 AT91C_PIO_PA18
|
||||
#define JOY0_BTN2 AT91C_PIO_PA17
|
||||
#define JOY0 (JOY0_UP|JOY0_DOWN|JOY0_LEFT|JOY0_RIGHT|JOY0_BTN1|JOY0_BTN2)
|
||||
|
||||
// chip selects for FPGA communication
|
||||
#define FPGA0 AT91C_PIO_PA10
|
||||
#define FPGA1 AT91C_PIO_PA3
|
||||
#define FPGA2 AT91C_PIO_PA2
|
||||
|
||||
#define FPGA3 AT91C_PIO_PA9 // same as ALTERA_DATA0
|
||||
#else
|
||||
|
||||
#error "Undefined setup!"
|
||||
#endif
|
||||
|
||||
#define VBL AT91C_PIO_PA7
|
||||
|
||||
void USART_Init(unsigned long baudrate);
|
||||
void USART_Write(unsigned char c) RAMFUNC;
|
||||
|
||||
static inline unsigned char SPI(unsigned char outByte) {
|
||||
while (!(*AT91C_SPI_SR & AT91C_SPI_TDRE));
|
||||
*AT91C_SPI_TDR = outByte;
|
||||
while (!(*AT91C_SPI_SR & AT91C_SPI_RDRF));
|
||||
return((unsigned char)*AT91C_SPI_RDR);
|
||||
}
|
||||
|
||||
#define SPI_SDC_CLK_VALUE 2 // 24 Mhz
|
||||
#define SPI_MMC_CLK_VALUE 3 // 16 Mhz
|
||||
#define SPI_SLOW_CLK_VALUE 120 // 400kHz
|
||||
|
||||
static inline void SPI_Wait4XferEnd() {
|
||||
while (!(*AT91C_SPI_SR & AT91C_SPI_TXEMPTY));
|
||||
|
||||
/* Clear any data left in the receiver */
|
||||
(void)*AT91C_SPI_RDR;
|
||||
(void)*AT91C_SPI_RDR;
|
||||
}
|
||||
|
||||
static inline void EnableCard() {
|
||||
*AT91C_PIOA_CODR = MMC_SEL; // clear output (MMC chip select enabled)
|
||||
}
|
||||
|
||||
static inline void DisableCard() {
|
||||
SPI_Wait4XferEnd();
|
||||
*AT91C_PIOA_SODR = MMC_SEL; // set output (MMC chip select disabled)
|
||||
SPI(0xFF);
|
||||
SPI_Wait4XferEnd();
|
||||
}
|
||||
|
||||
|
||||
void SPI_Init(void);
|
||||
// unsigned char SPI(unsigned char outByte);
|
||||
void EnableFpga(void);
|
||||
void DisableFpga(void);
|
||||
void EnableOsd(void);
|
||||
void DisableOsd(void);
|
||||
unsigned long CheckButton(void);
|
||||
void Timer_Init(void);
|
||||
unsigned long GetTimer(unsigned long offset);
|
||||
unsigned long CheckTimer(unsigned long t);
|
||||
void WaitTimer(unsigned long time);
|
||||
|
||||
void SPI_slow();
|
||||
void SPI_fast();
|
||||
void SPI_fast_mmc();
|
||||
void TIMER_wait(unsigned long ms);
|
||||
void EnableDMode();
|
||||
void DisableDMode();
|
||||
void SPI_block(unsigned short num);
|
||||
|
||||
#define SPI_BLOCK_READ
|
||||
RAMFUNC void SPI_block_read(char *addr);
|
||||
|
||||
#ifdef FPGA3
|
||||
// the MiST has the user inout on the arm controller
|
||||
void EnableIO(void);
|
||||
void DisableIO(void);
|
||||
#endif
|
||||
|
||||
#define DEBUG_FUNC_IN()
|
||||
|
||||
#endif // HARDWARE_H
|
||||
962
hdd.c
Normal file
962
hdd.c
Normal file
@@ -0,0 +1,962 @@
|
||||
/*
|
||||
Copyright 2008, 2009 Jakub Bednarski
|
||||
|
||||
This file is part of Minimig
|
||||
|
||||
Minimig is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Minimig is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// 2009-11-22 - read/write multiple implemented
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include "AT91SAM7S256.h"
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "errors.h"
|
||||
#include "hardware.h"
|
||||
#include "fat.h"
|
||||
#include "hdd.h"
|
||||
#include "hdd_internal.h"
|
||||
#include "mmc.h"
|
||||
#include "menu.h"
|
||||
#include "fpga.h"
|
||||
#include "config.h"
|
||||
|
||||
// hardfile structure
|
||||
hdfTYPE hdf[2];
|
||||
|
||||
static void RDBChecksum(unsigned long *p)
|
||||
{
|
||||
unsigned long count=p[1];
|
||||
unsigned long c2;
|
||||
long result=0;
|
||||
p[2]=0;
|
||||
for(c2=0;c2<count;++c2)
|
||||
result+=p[c2];
|
||||
p[2]=(unsigned long)-result;
|
||||
}
|
||||
|
||||
|
||||
// If the hardfile doesn't have a RigidDiskBlock,
|
||||
// we synthesize one.
|
||||
static void FakeRDB(int unit,int block)
|
||||
{
|
||||
int i;
|
||||
// Start by clearing the sector buffer
|
||||
for(i=0;i<512;++i)
|
||||
sector_buffer[i]=0;
|
||||
|
||||
// If we're asked for LBA 0 we create an RDSK block, and if LBA 1, a PART block.
|
||||
switch(block)
|
||||
{
|
||||
case 0: // RDB
|
||||
{
|
||||
struct RigidDiskBlock *rdb=(struct RigidDiskBlock *)sector_buffer;
|
||||
rdb->rdb_ID = 'R'<<24 | 'D' << 16 | 'S' << 8 | 'K';
|
||||
|
||||
rdb->rdb_Summedlongs=0x40;
|
||||
rdb->rdb_HostID=0x07;
|
||||
rdb->rdb_BlockBytes=0x200;
|
||||
rdb->rdb_Flags=0x12; // (Disk ID valid, no LUNs after this one)
|
||||
rdb->rdb_BadBlockList=0xffffffff; // We don't provide a bad block list
|
||||
rdb->rdb_PartitionList=1;
|
||||
rdb->rdb_FileSysHeaderList=0xffffffff;
|
||||
rdb->rdb_DriveInit=0xffffffff;
|
||||
rdb->rdb_Reserved1[0]=0xffffffff;
|
||||
rdb->rdb_Reserved1[1]=0xffffffff;
|
||||
rdb->rdb_Reserved1[2]=0xffffffff;
|
||||
rdb->rdb_Reserved1[3]=0xffffffff;
|
||||
rdb->rdb_Reserved1[4]=0xffffffff;
|
||||
rdb->rdb_Reserved1[5]=0xffffffff;
|
||||
rdb->rdb_Cylinders=hdf[unit].cylinders;
|
||||
rdb->rdb_Sectors=hdf[unit].sectors;
|
||||
rdb->rdb_Heads=hdf[unit].heads;
|
||||
rdb->rdb_Interleave=1;
|
||||
rdb->rdb_Park=rdb->rdb_Cylinders;
|
||||
rdb->rdb_WritePreComp=rdb->rdb_Cylinders;
|
||||
rdb->rdb_ReducedWrite=rdb->rdb_Cylinders;
|
||||
rdb->rdb_StepRate=3;
|
||||
rdb->rdb_RDBBlocksLo=0;
|
||||
rdb->rdb_RDBBlocksHi=1;
|
||||
rdb->rdb_LoCylinder=1;
|
||||
rdb->rdb_HiCylinder=rdb->rdb_Cylinders-1;
|
||||
rdb->rdb_CylBlocks=rdb->rdb_Heads * rdb->rdb_Sectors;
|
||||
rdb->rdb_AutoParkSeconds=0;
|
||||
rdb->rdb_HighRDSKBlock=1;
|
||||
strcpy(rdb->rdb_DiskVendor,"Do not ");
|
||||
strcpy(rdb->rdb_DiskProduct, "repartition!");
|
||||
|
||||
RDBChecksum((unsigned long *)rdb);
|
||||
}
|
||||
break;
|
||||
case 1: // Partition
|
||||
{
|
||||
struct PartitionBlock *pb=(struct PartitionBlock *)sector_buffer;
|
||||
pb->pb_ID = 'P'<<24 | 'A' << 16 | 'R' << 8 | 'T';
|
||||
|
||||
pb->pb_Summedlongs=0x40;
|
||||
pb->pb_HostID=0x07;
|
||||
pb->pb_Next=0xffffffff;
|
||||
pb->pb_Flags=0x1; // Bootable
|
||||
pb->pb_DevFlags=0;
|
||||
strcpy(pb->pb_DriveName," DH0");
|
||||
pb->pb_DriveName[0]=3; // BCPL string
|
||||
|
||||
pb->pb_Environment.de_TableSize=0x10;
|
||||
pb->pb_Environment.de_SizeBlock=0x80;
|
||||
pb->pb_Environment.de_Surfaces=hdf[unit].heads;
|
||||
pb->pb_Environment.de_SectorPerBlock=1;
|
||||
pb->pb_Environment.de_BlocksPerTrack=hdf[unit].sectors;
|
||||
pb->pb_Environment.de_Reserved=2;
|
||||
pb->pb_Environment.de_LowCyl=1;
|
||||
pb->pb_Environment.de_HighCyl=hdf[unit].cylinders-1;
|
||||
pb->pb_Environment.de_NumBuffers=30;
|
||||
pb->pb_Environment.de_MaxTransfer=0xffffff;
|
||||
pb->pb_Environment.de_Mask=0x7ffffffe;
|
||||
pb->pb_Environment.de_DosType=0x444f5301;
|
||||
|
||||
RDBChecksum((unsigned long *)pb);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IdentifyDevice(unsigned short *pBuffer, unsigned char unit)
|
||||
{ // builds Identify Device struct
|
||||
char *p, i, x;
|
||||
unsigned long total_sectors = hdf[unit].cylinders * hdf[unit].heads * hdf[unit].sectors;
|
||||
|
||||
memset(pBuffer, 0, 512);
|
||||
|
||||
switch(hdf[unit].type)
|
||||
{
|
||||
case HDF_FILE | HDF_SYNTHRDB:
|
||||
case HDF_FILE:
|
||||
pBuffer[0] = 1 << 6; // hard disk
|
||||
pBuffer[1] = hdf[unit].cylinders; // cyl count
|
||||
pBuffer[3] = hdf[unit].heads; // head count
|
||||
pBuffer[6] = hdf[unit].sectors; // sectors per track
|
||||
// FIXME - can get serial no from card itself.
|
||||
memcpy((char*)&pBuffer[10], "1234567890ABCDEFGHIJ", 20); // serial number - byte swapped
|
||||
memcpy((char*)&pBuffer[23], ".100 ", 8); // firmware version - byte swapped
|
||||
p = (char*)&pBuffer[27];
|
||||
// FIXME - likewise the model name can be fetched from the card.
|
||||
if(hdf[unit].type & HDF_SYNTHRDB)
|
||||
{
|
||||
memcpy(p, "DON'T ", 40);
|
||||
p += 8;
|
||||
memcpy(p, "REPARTITION! ", 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(p, "YAQUBE ", 40); // model name - byte swapped
|
||||
p += 8;
|
||||
if (config.hardfile[unit].long_name[0])
|
||||
{
|
||||
for (i = 0; (x = config.hardfile[unit].long_name[i]) && i < 16; i++) // copy file name as model name
|
||||
p[i] = x;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(p, config.hardfile[unit].name, 8); // copy file name as model name
|
||||
}
|
||||
}
|
||||
// SwapBytes((char*)&pBuffer[27], 40); //not for 68000
|
||||
break;
|
||||
case HDF_CARD:
|
||||
case HDF_CARDPART0:
|
||||
case HDF_CARDPART1:
|
||||
case HDF_CARDPART2:
|
||||
case HDF_CARDPART3:
|
||||
pBuffer[0] = 1 << 6; // hard disk
|
||||
pBuffer[1] = hdf[unit].cylinders; // cyl count
|
||||
pBuffer[3] = hdf[unit].heads; // head count
|
||||
pBuffer[6] = hdf[unit].sectors; // sectors per track
|
||||
// FIXME - can get serial no from card itself.
|
||||
memcpy((char*)&pBuffer[10], "TC64MiniMigSD0 ", 20); // serial number - byte swapped
|
||||
pBuffer[23]+=hdf[unit].type-HDF_CARD;
|
||||
memcpy((char*)&pBuffer[23], ".100 ", 8); // firmware version - byte swapped
|
||||
p = (char*)&pBuffer[27];
|
||||
// FIXME - likewise the model name can be fetched from the card.
|
||||
memcpy(p, "YAQUBE ", 40); // model name - byte swapped
|
||||
p += 8;
|
||||
if(hdf[unit].type==HDF_CARD)
|
||||
memcpy(p, "SD/MMC Card", 11); // copy file name as model name
|
||||
else
|
||||
{
|
||||
memcpy(p, "Card Part 1", 11); // copy file name as model name
|
||||
p[10]+=hdf[unit].partition;
|
||||
}
|
||||
// SwapBytes((char*)&pBuffer[27], 40); //not for 68000
|
||||
break;
|
||||
}
|
||||
|
||||
pBuffer[47] = 0x8010; //maximum sectors per block in Read/Write Multiple command
|
||||
pBuffer[53] = 1;
|
||||
pBuffer[54] = hdf[unit].cylinders;
|
||||
pBuffer[55] = hdf[unit].heads;
|
||||
pBuffer[56] = hdf[unit].sectors;
|
||||
pBuffer[57] = (unsigned short)total_sectors;
|
||||
pBuffer[58] = (unsigned short)(total_sectors >> 16);
|
||||
}
|
||||
|
||||
unsigned long chs2lba(unsigned short cylinder, unsigned char head, unsigned short sector, unsigned char unit)
|
||||
{
|
||||
return(cylinder * hdf[unit].heads + head) * hdf[unit].sectors + sector - 1;
|
||||
}
|
||||
|
||||
void WriteTaskFile(unsigned char error, unsigned char sector_count, unsigned char sector_number, unsigned char cylinder_low, unsigned char cylinder_high, unsigned char drive_head)
|
||||
{
|
||||
EnableFpga();
|
||||
|
||||
SPI(CMD_IDE_REGS_WR); // write task file registers command
|
||||
SPI(0x00);
|
||||
SPI(0x00); // dummy
|
||||
SPI(0x00);
|
||||
SPI(0x00); // dummy
|
||||
SPI(0x00);
|
||||
|
||||
|
||||
|
||||
SPI(0x00); // dummy
|
||||
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(error); // error
|
||||
SPI(0x00);
|
||||
SPI(sector_count); // sector count
|
||||
SPI(0x00);
|
||||
SPI(sector_number); //sector number
|
||||
SPI(0x00);
|
||||
SPI(cylinder_low); // cylinder low
|
||||
SPI(0x00);
|
||||
SPI(cylinder_high); // cylinder high
|
||||
SPI(0x00);
|
||||
SPI(drive_head); // drive/head
|
||||
|
||||
DisableFpga();
|
||||
}
|
||||
|
||||
void WriteStatus(unsigned char status)
|
||||
{
|
||||
EnableFpga();
|
||||
|
||||
SPI(CMD_IDE_STATUS_WR);
|
||||
SPI(status);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
|
||||
DisableFpga();
|
||||
}
|
||||
|
||||
void HandleHDD(unsigned char c1, unsigned char c2)
|
||||
{
|
||||
unsigned short id[256];
|
||||
unsigned char tfr[8];
|
||||
unsigned short i;
|
||||
unsigned short sector;
|
||||
unsigned short cylinder;
|
||||
unsigned char head;
|
||||
unsigned char unit;
|
||||
unsigned short sector_count;
|
||||
unsigned short block_count;
|
||||
|
||||
if (c1 & CMD_IDECMD)
|
||||
{
|
||||
DISKLED_ON;
|
||||
EnableFpga();
|
||||
SPI(CMD_IDE_REGS_RD); // read task file registers
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
SPI(0);
|
||||
tfr[i] = SPI(0);
|
||||
}
|
||||
DisableFpga();
|
||||
|
||||
unit = tfr[6] & 0x10 ? 1 : 0; // master/slave selection
|
||||
|
||||
if (0)
|
||||
{
|
||||
printf("IDE:");
|
||||
for (i = 1; i < 7; i++)
|
||||
printf("%02X.",tfr[i]);
|
||||
printf("%02X\r", tfr[7]);
|
||||
}
|
||||
if ((tfr[7] & 0xF0) == ACMD_RECALIBRATE) // Recalibrate 0x10-0x1F (class 3 command: no data)
|
||||
{
|
||||
printf("Recalibrate\r");
|
||||
WriteTaskFile(0, 0, 1, 0, 0, tfr[6] & 0xF0);
|
||||
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
|
||||
}
|
||||
else if (tfr[7] == ACMD_IDENTIFY_DEVICE) // Identify Device
|
||||
{
|
||||
printf("Identify Device\r");
|
||||
IdentifyDevice(id, unit);
|
||||
WriteTaskFile(0, tfr[2], tfr[3], tfr[4], tfr[5], tfr[6]);
|
||||
WriteStatus(IDE_STATUS_RDY); // pio in (class 1) command type
|
||||
EnableFpga();
|
||||
SPI(CMD_IDE_DATA_WR); // write data command
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
SPI((unsigned char)id[i]);
|
||||
SPI((unsigned char)(id[i] >> 8));
|
||||
}
|
||||
DisableFpga();
|
||||
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
|
||||
}
|
||||
else if (tfr[7] == ACMD_INITIALIZE_DEVICE_PARAMETERS) // Initiallize Device Parameters
|
||||
{
|
||||
printf("Initialize Device Parameters\r");
|
||||
printf("IDE:");
|
||||
for (i = 1; i < 7; i++)
|
||||
printf("%02X.", tfr[i]);
|
||||
printf("%02X\r", tfr[7]);
|
||||
WriteTaskFile(0, tfr[2], tfr[3], tfr[4], tfr[5], tfr[6]);
|
||||
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
|
||||
}
|
||||
else if (tfr[7] == ACMD_READ_SECTORS) // Read Sectors
|
||||
{
|
||||
long lba;
|
||||
|
||||
sector = tfr[3];
|
||||
cylinder = tfr[4] | (tfr[5] << 8);
|
||||
head = tfr[6] & 0x0F;
|
||||
sector_count = tfr[2];
|
||||
if (sector_count == 0)
|
||||
sector_count = 0x100;
|
||||
|
||||
switch(hdf[unit].type)
|
||||
{
|
||||
case HDF_FILE | HDF_SYNTHRDB:
|
||||
case HDF_FILE:
|
||||
lba=chs2lba(cylinder, head, sector, unit);
|
||||
if (hdf[unit].file.size)
|
||||
HardFileSeek(&hdf[unit], (lba+hdf[unit].offset) < 0 ? 0 : lba+hdf[unit].offset);
|
||||
|
||||
while (sector_count)
|
||||
{
|
||||
// decrease sector count
|
||||
if(sector_count!=1)
|
||||
{
|
||||
if (sector == hdf[unit].sectors)
|
||||
{
|
||||
sector = 1;
|
||||
head++;
|
||||
if (head == hdf[unit].heads)
|
||||
{
|
||||
head = 0;
|
||||
cylinder++;
|
||||
}
|
||||
}
|
||||
else
|
||||
sector++;
|
||||
}
|
||||
|
||||
if((lba+hdf[unit].offset)<0)
|
||||
{
|
||||
FakeRDB(unit,lba);
|
||||
|
||||
WriteTaskFile(0, tfr[2], sector, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), (tfr[6] & 0xF0) | head);
|
||||
WriteStatus(IDE_STATUS_RDY); // pio in (class 1) command type
|
||||
EnableFpga();
|
||||
SPI(CMD_IDE_DATA_WR); // write data command
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
for (i = 0; i < 512; i++)
|
||||
{
|
||||
SPI(sector_buffer[i]);
|
||||
}
|
||||
DisableFpga();
|
||||
WriteStatus(sector_count==1 ? IDE_STATUS_IRQ|IDE_STATUS_END : IDE_STATUS_IRQ);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteStatus(IDE_STATUS_RDY); // pio in (class 1) command type
|
||||
WriteTaskFile(0, tfr[2], sector, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), (tfr[6] & 0xF0) | head);
|
||||
|
||||
while (!(GetFPGAStatus() & CMD_IDECMD)); // wait for empty sector buffer
|
||||
|
||||
WriteStatus(IDE_STATUS_IRQ);
|
||||
|
||||
if (hdf[unit].file.size)
|
||||
{
|
||||
// FileRead(&hdf[unit].file, NULL);
|
||||
FileRead(&hdf[unit].file, 0);
|
||||
FileSeek(&hdf[unit].file, 1, SEEK_CUR);
|
||||
}
|
||||
}
|
||||
lba++;
|
||||
sector_count--; // decrease sector count
|
||||
}
|
||||
break;
|
||||
case HDF_CARD:
|
||||
case HDF_CARDPART0:
|
||||
case HDF_CARDPART1:
|
||||
case HDF_CARDPART2:
|
||||
case HDF_CARDPART3:
|
||||
{
|
||||
WriteStatus(IDE_STATUS_RDY); // pio in (class 1) command type
|
||||
lba=chs2lba(cylinder, head, sector, unit)+hdf[unit].offset;
|
||||
while (sector_count)
|
||||
{
|
||||
// decrease sector count
|
||||
if(sector_count!=1)
|
||||
{
|
||||
if (sector == hdf[unit].sectors)
|
||||
{
|
||||
sector = 1;
|
||||
head++;
|
||||
if (head == hdf[unit].heads)
|
||||
{
|
||||
head = 0;
|
||||
cylinder++;
|
||||
}
|
||||
}
|
||||
else
|
||||
sector++;
|
||||
}
|
||||
|
||||
WriteTaskFile(0, tfr[2], sector, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), (tfr[6] & 0xF0) | head);
|
||||
|
||||
while (!(GetFPGAStatus() & CMD_IDECMD)); // wait for empty sector buffer
|
||||
WriteStatus(IDE_STATUS_IRQ);
|
||||
MMC_Read(lba,0);
|
||||
++lba;
|
||||
--sector_count;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (tfr[7] == ACMD_SET_MULTIPLE_MODE) // Set Multiple Mode
|
||||
{
|
||||
hdf[unit].sectors_per_block = tfr[2];
|
||||
|
||||
printf("Set Multiple Mode\r");
|
||||
printf("IDE:");
|
||||
for (i = 1; i < 7; i++)
|
||||
printf("%02X.", tfr[i]);
|
||||
printf("%02X\r", tfr[7]);
|
||||
|
||||
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
|
||||
}
|
||||
else if (tfr[7] == ACMD_READ_MULTIPLE) // Read Multiple Sectors (multiple sector transfer per IRQ)
|
||||
{
|
||||
long lba;
|
||||
WriteStatus(IDE_STATUS_RDY); // pio in (class 1) command type
|
||||
|
||||
sector = tfr[3];
|
||||
cylinder = tfr[4] | (tfr[5] << 8);
|
||||
head = tfr[6] & 0x0F;
|
||||
sector_count = tfr[2];
|
||||
if (sector_count == 0)
|
||||
sector_count = 0x100;
|
||||
|
||||
switch(hdf[unit].type)
|
||||
{
|
||||
case HDF_FILE | HDF_SYNTHRDB:
|
||||
case HDF_FILE:
|
||||
lba=chs2lba(cylinder, head, sector, unit);
|
||||
if (hdf[unit].file.size)
|
||||
HardFileSeek(&hdf[unit], (lba+hdf[unit].offset) < 0 ? 0 : lba + hdf[unit].offset);
|
||||
// FIXME - READM could cross the fake RDB -> real disk boundary.
|
||||
// FIXME - but first we should make some attempt to generate fake RGB in multiple mode.
|
||||
|
||||
while (sector_count)
|
||||
{
|
||||
while (!(GetFPGAStatus() & CMD_IDECMD)); // wait for empty sector buffer
|
||||
|
||||
block_count = sector_count;
|
||||
if (block_count > hdf[unit].sectors_per_block)
|
||||
block_count = hdf[unit].sectors_per_block;
|
||||
|
||||
WriteStatus(IDE_STATUS_IRQ);
|
||||
|
||||
if (hdf[unit].file.size)
|
||||
// FileReadEx(&hdf[unit].file, NULL, block_count); // NULL enables direct transfer to the FPGA
|
||||
FileReadEx(&hdf[unit].file, 0, block_count); // NULL enables direct transfer to the FPGA
|
||||
|
||||
while (block_count--)
|
||||
{
|
||||
if(sector_count!=1)
|
||||
{
|
||||
if (sector == hdf[unit].sectors)
|
||||
{
|
||||
sector = 1;
|
||||
head++;
|
||||
if (head == hdf[unit].heads)
|
||||
{
|
||||
head = 0;
|
||||
cylinder++;
|
||||
}
|
||||
}
|
||||
else
|
||||
sector++;
|
||||
}
|
||||
sector_count--;
|
||||
}
|
||||
WriteTaskFile(0, tfr[2], sector, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), (tfr[6] & 0xF0) | head);
|
||||
// WriteTaskFile(0, 0, sector, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), (tfr[6] & 0xF0) | head);
|
||||
}
|
||||
// WriteTaskFile(0, 0, sector, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), (tfr[6] & 0xF0) | head);
|
||||
break;
|
||||
case HDF_CARD:
|
||||
case HDF_CARDPART0:
|
||||
case HDF_CARDPART1:
|
||||
case HDF_CARDPART2:
|
||||
case HDF_CARDPART3:
|
||||
{
|
||||
long lba=chs2lba(cylinder, head, sector, unit)+hdf[unit].offset;
|
||||
while (sector_count)
|
||||
{
|
||||
while (!(GetFPGAStatus() & CMD_IDECMD)); // wait for empty sector buffer
|
||||
|
||||
block_count = sector_count;
|
||||
if (block_count > hdf[unit].sectors_per_block)
|
||||
block_count = hdf[unit].sectors_per_block;
|
||||
|
||||
WriteStatus(IDE_STATUS_IRQ);
|
||||
MMC_ReadMultiple(lba,0,block_count);
|
||||
lba+=block_count;
|
||||
|
||||
while (block_count--)
|
||||
{
|
||||
if(sector_count!=1)
|
||||
{
|
||||
if (sector == hdf[unit].sectors)
|
||||
{
|
||||
sector = 1;
|
||||
head++;
|
||||
if (head == hdf[unit].heads)
|
||||
{
|
||||
head = 0;
|
||||
cylinder++;
|
||||
}
|
||||
}
|
||||
else
|
||||
sector++;
|
||||
|
||||
}
|
||||
sector_count--;
|
||||
}
|
||||
WriteTaskFile(0, tfr[2], sector, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), (tfr[6] & 0xF0) | head);
|
||||
// WriteTaskFile(0, 0, sector, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), (tfr[6] & 0xF0) | head);
|
||||
}
|
||||
// WriteTaskFile(0, 0, sector, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), (tfr[6] & 0xF0) | head);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (tfr[7] == ACMD_WRITE_SECTORS) // write sectors
|
||||
{
|
||||
WriteStatus(IDE_STATUS_REQ); // pio out (class 2) command type
|
||||
|
||||
sector = tfr[3];
|
||||
cylinder = tfr[4] | (tfr[5] << 8);
|
||||
head = tfr[6] & 0x0F;
|
||||
sector_count = tfr[2];
|
||||
if (sector_count == 0)
|
||||
sector_count = 0x100;
|
||||
|
||||
long lba=chs2lba(cylinder, head, sector, unit);
|
||||
// if(hdf[unit].type>=HDF_CARDPART0)
|
||||
lba+=hdf[unit].offset;
|
||||
|
||||
if (hdf[unit].file.size) // File size will be 0 in direct card modes
|
||||
HardFileSeek(&hdf[unit], (lba>-1) ? lba : 0);
|
||||
|
||||
while (sector_count)
|
||||
{
|
||||
while (!(GetFPGAStatus() & CMD_IDEDAT)); // wait for full write buffer
|
||||
|
||||
// decrease sector count
|
||||
if(sector_count!=1)
|
||||
{
|
||||
if (sector == hdf[unit].sectors)
|
||||
{
|
||||
sector = 1;
|
||||
head++;
|
||||
if (head == hdf[unit].heads)
|
||||
{
|
||||
head = 0;
|
||||
cylinder++;
|
||||
}
|
||||
}
|
||||
else
|
||||
sector++;
|
||||
}
|
||||
|
||||
WriteTaskFile(0, tfr[2], sector, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), (tfr[6] & 0xF0) | head);
|
||||
|
||||
EnableFpga();
|
||||
SPI(CMD_IDE_DATA_RD); // read data command
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
for (i = 0; i < 512; i++)
|
||||
sector_buffer[i] = SPI(0xFF);
|
||||
DisableFpga();
|
||||
|
||||
sector_count--; // decrease sector count
|
||||
|
||||
if (sector_count)
|
||||
WriteStatus(IDE_STATUS_IRQ);
|
||||
else
|
||||
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
|
||||
|
||||
switch(hdf[unit].type)
|
||||
{
|
||||
case HDF_FILE | HDF_SYNTHRDB:
|
||||
case HDF_FILE:
|
||||
if (hdf[unit].file.size && (lba>-1)) // Don't attempt to write to fake RDB
|
||||
{
|
||||
FileWrite(&hdf[unit].file, sector_buffer);
|
||||
FileSeek(&hdf[unit].file, 1, SEEK_CUR);
|
||||
}
|
||||
++lba;
|
||||
break;
|
||||
case HDF_CARD:
|
||||
case HDF_CARDPART0:
|
||||
case HDF_CARDPART1:
|
||||
case HDF_CARDPART2:
|
||||
case HDF_CARDPART3:
|
||||
MMC_Write(lba,sector_buffer);
|
||||
++lba;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tfr[7] == ACMD_WRITE_MULTIPLE) // write sectors
|
||||
{
|
||||
WriteStatus(IDE_STATUS_REQ); // pio out (class 2) command type
|
||||
|
||||
sector = tfr[3];
|
||||
cylinder = tfr[4] | (tfr[5] << 8);
|
||||
head = tfr[6] & 0x0F;
|
||||
sector_count = tfr[2];
|
||||
if (sector_count == 0)
|
||||
sector_count = 0x100;
|
||||
|
||||
long lba=chs2lba(cylinder, head, sector, unit);
|
||||
// if(hdf[unit].type>=HDF_CARDPART0)
|
||||
lba+=hdf[unit].offset;
|
||||
|
||||
if (hdf[unit].file.size) // File size will be 0 in direct card modes
|
||||
HardFileSeek(&hdf[unit], (lba>-1) ? lba : 0);
|
||||
|
||||
while (sector_count)
|
||||
{
|
||||
block_count = sector_count;
|
||||
if (block_count > hdf[unit].sectors_per_block)
|
||||
block_count = hdf[unit].sectors_per_block;
|
||||
|
||||
while (block_count)
|
||||
{
|
||||
while (!(GetFPGAStatus() & CMD_IDEDAT)); // wait for full write buffer
|
||||
|
||||
// decrease sector count
|
||||
if(sector_count!=1)
|
||||
{
|
||||
if (sector == hdf[unit].sectors)
|
||||
{
|
||||
sector = 1;
|
||||
head++;
|
||||
if (head == hdf[unit].heads)
|
||||
{
|
||||
head = 0;
|
||||
cylinder++;
|
||||
}
|
||||
}
|
||||
else
|
||||
sector++;
|
||||
}
|
||||
|
||||
// WriteTaskFile(0, tfr[2], sector, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), (tfr[6] & 0xF0) | head);
|
||||
|
||||
EnableFpga();
|
||||
SPI(CMD_IDE_DATA_RD); // read data command
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
for (i = 0; i < 512; i++)
|
||||
sector_buffer[i] = SPI(0xFF);
|
||||
DisableFpga();
|
||||
switch(hdf[unit].type)
|
||||
{
|
||||
case HDF_FILE | HDF_SYNTHRDB:
|
||||
case HDF_FILE:
|
||||
if (hdf[unit].file.size && (lba>-1))
|
||||
{
|
||||
FileWrite(&hdf[unit].file, sector_buffer);
|
||||
FileSeek(&hdf[unit].file, 1, SEEK_CUR);
|
||||
}
|
||||
++lba;
|
||||
break;
|
||||
case HDF_CARD:
|
||||
case HDF_CARDPART0:
|
||||
case HDF_CARDPART1:
|
||||
case HDF_CARDPART2:
|
||||
case HDF_CARDPART3:
|
||||
MMC_Write(lba,sector_buffer);
|
||||
++lba;
|
||||
break;
|
||||
}
|
||||
block_count--; // decrease block count
|
||||
sector_count--; // decrease sector count
|
||||
}
|
||||
WriteTaskFile(0, tfr[2], sector, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), (tfr[6] & 0xF0) | head);
|
||||
|
||||
if (sector_count)
|
||||
WriteStatus(IDE_STATUS_IRQ);
|
||||
else
|
||||
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Unknown ATA command\r");
|
||||
|
||||
printf("IDE:");
|
||||
for (i = 1; i < 7; i++)
|
||||
printf("%02X.", tfr[i]);
|
||||
printf("%02X\r", tfr[7]);
|
||||
WriteTaskFile(0x04, tfr[2], tfr[3], tfr[4], tfr[5], tfr[6]);
|
||||
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ | IDE_STATUS_ERR);
|
||||
}
|
||||
DISKLED_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
void GetHardfileGeometry(hdfTYPE *pHDF)
|
||||
{ // this function comes from WinUAE, should return the same CHS as WinUAE
|
||||
|
||||
unsigned long total=0;
|
||||
unsigned long i, head, cyl, spt;
|
||||
unsigned long sptt[] = { 63, 127, 255, 0 };
|
||||
|
||||
switch(pHDF->type)
|
||||
{
|
||||
case (HDF_FILE | HDF_SYNTHRDB):
|
||||
if (pHDF->file.size == 0)
|
||||
return;
|
||||
total = pHDF->file.size / 512;
|
||||
pHDF->heads = 1;
|
||||
pHDF->sectors = 32;
|
||||
pHDF->cylinders = total/32 + 1; // Add a cylinder for the fake RDB.
|
||||
return;
|
||||
case HDF_FILE:
|
||||
if (pHDF->file.size == 0)
|
||||
return;
|
||||
total = pHDF->file.size / 512;
|
||||
break;
|
||||
case HDF_CARD:
|
||||
total = MMC_GetCapacity(); // GetCapacity returns number of blocks, not bytes.
|
||||
break;
|
||||
case HDF_CARDPART0:
|
||||
case HDF_CARDPART1:
|
||||
case HDF_CARDPART2:
|
||||
case HDF_CARDPART3:
|
||||
total = partitions[pHDF->partition].sectors;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; sptt[i] != 0; i++)
|
||||
{
|
||||
spt = sptt[i];
|
||||
for (head = 4; head <= 16; head++)
|
||||
{
|
||||
cyl = total / (head * spt);
|
||||
if (total <= 1024 * 1024)
|
||||
{
|
||||
if (cyl <= 1023)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cyl < 16383)
|
||||
break;
|
||||
if (cyl < 32767 && head >= 5)
|
||||
break;
|
||||
if (cyl <= 65535) // Should there some head constraint here?
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (head <= 16)
|
||||
break;
|
||||
}
|
||||
pHDF->cylinders = (unsigned short)cyl;
|
||||
pHDF->heads = (unsigned short)head;
|
||||
pHDF->sectors = (unsigned short)spt;
|
||||
}
|
||||
|
||||
void BuildHardfileIndex(hdfTYPE *pHDF)
|
||||
{
|
||||
// builds index to speed up hard file seek
|
||||
|
||||
fileTYPE *file = &pHDF->file;
|
||||
unsigned long *index = pHDF->index;
|
||||
unsigned long i;
|
||||
unsigned long j;
|
||||
|
||||
pHDF->index_size = 16; // indexing size
|
||||
j = 1 << pHDF->index_size;
|
||||
i = pHDF->file.size >> 10; // divided by index table size (1024)
|
||||
while (j < i) // find greater or equal power of two
|
||||
{
|
||||
j <<= 1;
|
||||
pHDF->index_size++;
|
||||
}
|
||||
|
||||
for (i = 0; i < file->size; i += j)
|
||||
{
|
||||
FileSeek(file, i >> 9, SEEK_SET); // FileSeek seeks in 512-byte sectors
|
||||
*index++ = file->cluster;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char HardFileSeek(hdfTYPE *pHDF, unsigned long lba)
|
||||
{
|
||||
if ((pHDF->file.sector ^ lba) & cluster_mask)
|
||||
{ // different clusters
|
||||
if ((pHDF->file.sector > lba) || ((pHDF->file.sector ^ lba) & (cluster_mask << (fat32 ? 7 : 8)))) // 7: 128 FAT32 links per sector, 8: 256 FAT16 links per sector
|
||||
{ // requested cluster lies before current pointer position or in different FAT sector
|
||||
pHDF->file.cluster = pHDF->index[lba >> (pHDF->index_size - 9)];// minus 9 because lba is in 512-byte sectors
|
||||
pHDF->file.sector = lba & (-1 << (pHDF->index_size - 9));
|
||||
}
|
||||
}
|
||||
return FileSeek(&pHDF->file, lba, SEEK_SET);
|
||||
}
|
||||
|
||||
unsigned char OpenHardfile(unsigned char unit)
|
||||
{
|
||||
unsigned long time;
|
||||
char filename[12];
|
||||
|
||||
switch(config.hardfile[unit].enabled)
|
||||
{
|
||||
case HDF_FILE | HDF_SYNTHRDB:
|
||||
case HDF_FILE:
|
||||
hdf[unit].type=config.hardfile[unit].enabled;
|
||||
strncpy(filename, config.hardfile[unit].name, 8);
|
||||
strcpy(&filename[8], "HDF");
|
||||
|
||||
if (filename[0])
|
||||
{
|
||||
if (FileOpen(&hdf[unit].file, filename))
|
||||
{
|
||||
GetHardfileGeometry(&hdf[unit]);
|
||||
|
||||
printf("HARDFILE %d:\r", unit);
|
||||
printf("file: \"%.8s.%.3s\"\r", hdf[unit].file.name, &hdf[unit].file.name[8]);
|
||||
printf("size: %lu (%lu MB)\r", hdf[unit].file.size, hdf[unit].file.size >> 20);
|
||||
printf("CHS: %u.%u.%u", hdf[unit].cylinders, hdf[unit].heads, hdf[unit].sectors);
|
||||
printf(" (%lu MB)\r", ((((unsigned long) hdf[unit].cylinders) * hdf[unit].heads * hdf[unit].sectors) >> 11));
|
||||
|
||||
time = GetTimer(0);
|
||||
BuildHardfileIndex(&hdf[unit]);
|
||||
time = GetTimer(0) - time;
|
||||
printf("Hardfile indexed in %lu ms\r", time >> 16);
|
||||
|
||||
if(config.hardfile[unit].enabled & HDF_SYNTHRDB)
|
||||
hdf[unit].offset=-(hdf[unit].heads*hdf[unit].sectors);
|
||||
else
|
||||
hdf[unit].offset=0;
|
||||
|
||||
config.hardfile[unit].present = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HDF_CARD:
|
||||
hdf[unit].type=HDF_CARD;
|
||||
config.hardfile[unit].present = 1;
|
||||
hdf[unit].file.size=0;
|
||||
hdf[unit].offset=0;
|
||||
GetHardfileGeometry(&hdf[unit]);
|
||||
return 1;
|
||||
break;
|
||||
case HDF_CARDPART0:
|
||||
case HDF_CARDPART1:
|
||||
case HDF_CARDPART2:
|
||||
case HDF_CARDPART3:
|
||||
hdf[unit].type=config.hardfile[unit].enabled;
|
||||
hdf[unit].partition=hdf[unit].type-HDF_CARDPART0;
|
||||
config.hardfile[unit].present = 1;
|
||||
hdf[unit].file.size=0;
|
||||
hdf[unit].offset=partitions[hdf[unit].partition].startlba;
|
||||
GetHardfileGeometry(&hdf[unit]);
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
config.hardfile[unit].present = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
fileTYPE rdbfile; // We scan for RDB without mounting the file as a unit, so need a file struct specifically for this task.
|
||||
|
||||
unsigned char GetHDFFileType(char *filename)
|
||||
{
|
||||
if(FileOpen(&rdbfile,filename))
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<16;++i)
|
||||
{
|
||||
FileRead(&rdbfile,sector_buffer);
|
||||
FileSeek(&rdbfile,512,SEEK_CUR);
|
||||
if(sector_buffer[0]=='R' && sector_buffer[1]=='D' && sector_buffer[2]=='S' && sector_buffer[3]=='K')
|
||||
return(HDF_FILETYPE_RDB);
|
||||
if(sector_buffer[0]=='D' && sector_buffer[1]=='O' && sector_buffer[2]=='S')
|
||||
return(HDF_FILETYPE_DOS);
|
||||
if(sector_buffer[0]=='P' && sector_buffer[1]=='F' && sector_buffer[2]=='S')
|
||||
return(HDF_FILETYPE_DOS);
|
||||
if(sector_buffer[0]=='S' && sector_buffer[1]=='F' && sector_buffer[2]=='S')
|
||||
return(HDF_FILETYPE_DOS);
|
||||
}
|
||||
return(HDF_FILETYPE_UNKNOWN);
|
||||
}
|
||||
return(HDF_FILETYPE_NOTFOUND);
|
||||
}
|
||||
|
||||
|
||||
70
hdd.h
Normal file
70
hdd.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#define CMD_IDECMD 0x04
|
||||
#define CMD_IDEDAT 0x08
|
||||
|
||||
#define CMD_IDE_REGS_RD 0x80
|
||||
#define CMD_IDE_REGS_WR 0x90
|
||||
#define CMD_IDE_DATA_WR 0xA0
|
||||
#define CMD_IDE_DATA_RD 0xB0
|
||||
#define CMD_IDE_STATUS_WR 0xF0
|
||||
|
||||
#define IDE_STATUS_END 0x80
|
||||
#define IDE_STATUS_IRQ 0x10
|
||||
#define IDE_STATUS_RDY 0x08
|
||||
#define IDE_STATUS_REQ 0x04
|
||||
#define IDE_STATUS_ERR 0x01
|
||||
|
||||
#define ACMD_RECALIBRATE 0x10
|
||||
#define ACMD_IDENTIFY_DEVICE 0xEC
|
||||
#define ACMD_INITIALIZE_DEVICE_PARAMETERS 0x91
|
||||
#define ACMD_READ_SECTORS 0x20
|
||||
#define ACMD_WRITE_SECTORS 0x30
|
||||
#define ACMD_READ_MULTIPLE 0xC4
|
||||
#define ACMD_WRITE_MULTIPLE 0xC5
|
||||
#define ACMD_SET_MULTIPLE_MODE 0xC6
|
||||
|
||||
#define HDF_DISABLED 0
|
||||
#define HDF_FILE 1
|
||||
#define HDF_CARD 2
|
||||
#define HDF_CARDPART0 3
|
||||
#define HDF_CARDPART1 4
|
||||
#define HDF_CARDPART2 5
|
||||
#define HDF_CARDPART3 6
|
||||
#define HDF_TYPEMASK 15
|
||||
#define HDF_SYNTHRDB 128 // Flag to indicate whether we should auto-synthesize a RigidDiskBlock
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int type; // Are we using a file, the entire SD card or a partition on the SD card?
|
||||
fileTYPE file;
|
||||
unsigned short cylinders;
|
||||
unsigned short heads;
|
||||
unsigned short sectors;
|
||||
unsigned short sectors_per_block;
|
||||
unsigned short partition; // Partition no.
|
||||
long offset; // If a partition, the lba offset of the partition. Can be negative if we've synthesized an RDB.
|
||||
unsigned long index[1024];
|
||||
unsigned long index_size;
|
||||
} hdfTYPE;
|
||||
|
||||
void IdentifyDevice(unsigned short *pBuffer, unsigned char unit);
|
||||
unsigned long chs2lba(unsigned short cylinder, unsigned char head, unsigned short sector, unsigned char unit);
|
||||
void WriteTaskFile(unsigned char error, unsigned char sector_count, unsigned char sector_number, unsigned char cylinder_low, unsigned char cylinder_high, unsigned char drive_head);
|
||||
void WriteStatus(unsigned char status);
|
||||
void HandleHDD(unsigned char c1, unsigned char c2);
|
||||
void GetHardfileGeometry(hdfTYPE *hdf);
|
||||
void BuildHardfileIndex(hdfTYPE *hdf);
|
||||
unsigned char HardFileSeek(hdfTYPE *hdf, unsigned long lba);
|
||||
unsigned char OpenHardfile(unsigned char unit);
|
||||
|
||||
#define HDF_FILETYPE_UNKNOWN 0
|
||||
#define HDF_FILETYPE_NOTFOUND 1
|
||||
#define HDF_FILETYPE_RDB 2
|
||||
#define HDF_FILETYPE_DOS 3
|
||||
|
||||
unsigned char GetHDFFileType(char *filename);
|
||||
|
||||
extern char debugmsg[40];
|
||||
extern char debugmsg2[40];
|
||||
|
||||
extern hdfTYPE hdf[2];
|
||||
|
||||
88
hdd_internal.h
Normal file
88
hdd_internal.h
Normal file
@@ -0,0 +1,88 @@
|
||||
#ifndef HDD_INTERNAL_H
|
||||
#define HDD_INTERNAL_H
|
||||
|
||||
// Structure definitions for RDB emulation.
|
||||
// For hardfiles that have no RDB information, we'll just create a single-partition RDB and Part block
|
||||
// on blocks 0 and 1. All other blocks within the first cylinder will be translated into the hardfile
|
||||
|
||||
struct RigidDiskBlock {
|
||||
unsigned long rdb_ID; // "RDSK"
|
||||
unsigned long rdb_Summedlongs; // 0x40
|
||||
long rdb_ChkSum; // Sum to zero
|
||||
unsigned long rdb_HostID; // 0x07
|
||||
unsigned long rdb_BlockBytes; // 0x200
|
||||
unsigned long rdb_Flags; // 0x12 (Disk ID valid, no LUNs after this one)
|
||||
unsigned long rdb_BadBlockList; // -1 since we don't provide one
|
||||
unsigned long rdb_PartitionList; // 1
|
||||
unsigned long rdb_FileSysHeaderList; // -1
|
||||
unsigned long rdb_DriveInit; // -1
|
||||
unsigned long rdb_Reserved1[6]; // 0xffffffff
|
||||
unsigned long rdb_Cylinders;
|
||||
unsigned long rdb_Sectors;
|
||||
unsigned long rdb_Heads;
|
||||
unsigned long rdb_Interleave; // 1
|
||||
unsigned long rdb_Park; // =Cylinder count
|
||||
unsigned long rdb_Reserved2[3];
|
||||
unsigned long rdb_WritePreComp; // High cylinder ?
|
||||
unsigned long rdb_ReducedWrite; // High cylinder ?
|
||||
unsigned long rdb_StepRate; // 3 ?
|
||||
unsigned long rdb_Reserved3[5];
|
||||
unsigned long rdb_RDBBlocksLo; // block zero
|
||||
unsigned long rdb_RDBBlocksHi; // block one
|
||||
unsigned long rdb_LoCylinder; // 1
|
||||
unsigned long rdb_HiCylinder; // From the hardfile: cylinder count -1
|
||||
unsigned long rdb_CylBlocks; // From the hardfile: heads * sectors
|
||||
unsigned long rdb_AutoParkSeconds; // zero
|
||||
unsigned long rdb_HighRDSKBlock; // 1
|
||||
unsigned long rdb_Reserved4;
|
||||
char rdb_DiskVendor[8]; // "Don't"
|
||||
char rdb_DiskProduct[16]; // " repartition!"
|
||||
char rdb_DiskRevision[4];
|
||||
char rdb_ControllerVendor[8];
|
||||
char rdb_ControllerProduct[16];
|
||||
char rdb_ControllerRevision[4];
|
||||
unsigned long rdb_Reserved5[10];
|
||||
};
|
||||
|
||||
struct DosEnvec {
|
||||
unsigned long de_TableSize; // Size of Environment vector - 0x10
|
||||
unsigned long de_SizeBlock; // in longwords - 0x80
|
||||
unsigned long de_SecOrg; // 0
|
||||
unsigned long de_Surfaces; // Heads?
|
||||
unsigned long de_SectorPerBlock; // 1
|
||||
unsigned long de_BlocksPerTrack;
|
||||
unsigned long de_Reserved; // 2 ?
|
||||
unsigned long de_PreAlloc; // 0
|
||||
unsigned long de_Interleave; // 0
|
||||
unsigned long de_LowCyl;
|
||||
unsigned long de_HighCyl;
|
||||
unsigned long de_NumBuffers; // 30
|
||||
unsigned long de_BufMemType; // 0 - any available
|
||||
unsigned long de_MaxTransfer; // 0x00ffffff
|
||||
unsigned long de_Mask; // 0x7ffffffe
|
||||
long de_BootPri; // 0
|
||||
unsigned long de_DosType; // 0x444f5301 or 3
|
||||
// Extra fields
|
||||
unsigned long de_Baud;
|
||||
unsigned long de_Control;
|
||||
unsigned long de_BootBlocks;
|
||||
};
|
||||
|
||||
|
||||
struct PartitionBlock {
|
||||
unsigned long pb_ID; // "PART"
|
||||
unsigned long pb_Summedlongs; // 0x40
|
||||
long pb_ChkSum; // Sum to zero
|
||||
unsigned long pb_HostID; // 0x07
|
||||
unsigned long pb_Next; // -1
|
||||
unsigned long pb_Flags; // 1 - Bootable
|
||||
unsigned long pb_Reserved1[2]; // 0
|
||||
unsigned long pb_DevFlags; // 0
|
||||
char pb_DriveName[32]; // 0x03"DH0"
|
||||
unsigned long pb_Reserved2[15];
|
||||
struct DosEnvec pb_Environment;
|
||||
unsigned long pb_EReserved[12]; /* reserved for future environment vector */
|
||||
};
|
||||
|
||||
#endif /* HDD_INTERNAL_H */
|
||||
|
||||
305
keycodes.h
Normal file
305
keycodes.h
Normal file
@@ -0,0 +1,305 @@
|
||||
// http://wiki.amigaos.net/index.php/Keymap_Library
|
||||
// http://www.win.tue.nl/~aeb/linux/kbd/scancodes-14.html
|
||||
|
||||
#include "osd.h"
|
||||
|
||||
#define MISS 0xff
|
||||
#define KEYCODE_MAX (0x6f)
|
||||
|
||||
// The original minimig had the keyboard connected to the FPGA. Thus all key events (even for OSD)
|
||||
// came from the FPGA core. The MIST has the keyboard attached to the arm controller. To be compatible
|
||||
// with the minimig core all keys (incl. OSD!) are forwarded to the FPGA and the OSD keys are returned.
|
||||
// These keys are tagged with the "OSD" flag
|
||||
// The atari/mist core does not forwards keys through the FPGA but queues them inside the arm controller.
|
||||
// These keys are tagged with the "OSD_LOC" flag. The keycodes itself used are identical between OSD
|
||||
// and OSD_LOC
|
||||
|
||||
#define OSD 0x0100 // to be used by OSD, not the core itself
|
||||
#define OSD_LOC 0x0200 // OSD key not forwarded to core, but queued in arm controller
|
||||
#define CAPS_LOCK_TOGGLE 0x0400 // caps lock toggle behaviour
|
||||
#define NUM_LOCK_TOGGLE 0x0800
|
||||
|
||||
|
||||
// amiga unmapped:
|
||||
// 0x0d |
|
||||
// 0x5a KP-(
|
||||
// 0x5b KP-)
|
||||
// codes >= 0x69 are for OSD only and are not sent to the amiga itself
|
||||
|
||||
// keycode translation table
|
||||
const unsigned short usb2ami[] = {
|
||||
MISS, // 00: NoEvent
|
||||
MISS, // 01: Overrun Error
|
||||
MISS, // 02: POST fail
|
||||
MISS, // 03: ErrorUndefined
|
||||
0x20, // 04: a
|
||||
0x35, // 05: b
|
||||
0x33, // 06: c
|
||||
0x22, // 07: d
|
||||
0x12, // 08: e
|
||||
0x23, // 09: f
|
||||
0x24, // 0a: g
|
||||
0x25, // 0b: h
|
||||
0x17, // 0c: i
|
||||
0x26, // 0d: j
|
||||
0x27, // 0e: k
|
||||
0x28, // 0f: l
|
||||
0x37, // 10: m
|
||||
0x36, // 11: n
|
||||
0x18, // 12: o
|
||||
0x19, // 13: p
|
||||
0x10, // 14: q
|
||||
0x13, // 15: r
|
||||
0x21, // 16: s
|
||||
0x14, // 17: t
|
||||
0x16, // 18: u
|
||||
0x34, // 19: v
|
||||
0x11, // 1a: w
|
||||
0x32, // 1b: x
|
||||
0x15, // 1c: y
|
||||
0x31, // 1d: z
|
||||
0x01, // 1e: 1
|
||||
0x02, // 1f: 2
|
||||
0x03, // 20: 3
|
||||
0x04, // 21: 4
|
||||
0x05, // 22: 5
|
||||
0x06, // 23: 6
|
||||
0x07, // 24: 7
|
||||
0x08, // 25: 8
|
||||
0x09, // 26: 9
|
||||
0x0a, // 27: 0
|
||||
0x44, // 28: Return
|
||||
0x45, // 29: Escape
|
||||
0x41, // 2a: Backspace
|
||||
0x42, // 2b: Tab
|
||||
0x40, // 2c: Space
|
||||
0x0b, // 2d: -
|
||||
0x0c, // 2e: =
|
||||
0x1a, // 2f: [
|
||||
0x1b, // 30: ]
|
||||
MISS, // 31: backslash
|
||||
0x2b, // 32: Europe 1
|
||||
0x29, // 33: ;
|
||||
0x2a, // 34: '
|
||||
0x00, // 35: `
|
||||
0x38, // 36: ,
|
||||
0x39, // 37: .
|
||||
0x3a, // 38: /
|
||||
0x62 | CAPS_LOCK_TOGGLE, // 39: Caps Lock
|
||||
0x50, // 3a: F1
|
||||
0x51, // 3b: F2
|
||||
0x52, // 3c: F3
|
||||
0x53, // 3d: F4
|
||||
0x54, // 3e: F5
|
||||
0x55, // 3f: F6
|
||||
0x56, // 40: F7
|
||||
0x57, // 41: F8
|
||||
0x58, // 42: F9
|
||||
0x59, // 43: F10
|
||||
0x5f, // 44: F11
|
||||
0x69 | OSD, // 45: F12 (OSD)
|
||||
0x6e | OSD, // 46: Print Screen (OSD)
|
||||
0x69 | OSD, // 47: Scroll Lock (OSD)
|
||||
MISS, // 48: Pause
|
||||
MISS, // 49: Insert
|
||||
MISS, // 4a: Home
|
||||
0x6c | OSD, // 4b: Page Up (OSD)
|
||||
0x46, // 4c: Delete
|
||||
MISS, // 4d: End
|
||||
0x6d | OSD, // 4e: Page Down (OSD)
|
||||
0x4e, // 4f: Right Arrow
|
||||
0x4f, // 50: Left Arrow
|
||||
0x4d, // 51: Down Arrow
|
||||
0x4c, // 52: Up Arrow
|
||||
NUM_LOCK_TOGGLE, // 53: Num Lock
|
||||
0x5c, // 54: KP /
|
||||
0x5d, // 55: KP *
|
||||
0x4a, // 56: KP -
|
||||
0x5e, // 57: KP +
|
||||
MISS, // 58: KP Enter
|
||||
0x1d, // 59: KP 1
|
||||
0x1e, // 5a: KP 2
|
||||
0x1f, // 5b: KP 3
|
||||
0x2d, // 5c: KP 4
|
||||
0x2e, // 5d: KP 5
|
||||
0x2f, // 5e: KP 6
|
||||
0x3d, // 5f: KP 7
|
||||
0x3e, // 60: KP 8
|
||||
0x3f, // 61: KP 9
|
||||
0x0f, // 62: KP 0
|
||||
0x3c, // 63: KP .
|
||||
0x30, // 64: Europe 2
|
||||
MISS, // 65: App
|
||||
MISS, // 66: Power
|
||||
MISS, // 67: KP =
|
||||
MISS, // 68: F13
|
||||
MISS, // 69: F14
|
||||
MISS, // 6a: F15
|
||||
MISS, // 6b: F16
|
||||
MISS, // 6c: F17
|
||||
MISS, // 6d: F18
|
||||
MISS, // 6e: F19
|
||||
MISS // 6f: F20
|
||||
};
|
||||
|
||||
// unmapped atari keys:
|
||||
// 0x63 KP (
|
||||
// 0x64 KP )
|
||||
|
||||
// keycode translation table for atari
|
||||
const unsigned short usb2atari[] = {
|
||||
MISS, // 00: NoEvent
|
||||
MISS, // 01: Overrun Error
|
||||
MISS, // 02: POST fail
|
||||
MISS, // 03: ErrorUndefined
|
||||
0x1e, // 04: a
|
||||
0x30, // 05: b
|
||||
0x2e, // 06: c
|
||||
0x20, // 07: d
|
||||
0x12, // 08: e
|
||||
0x21, // 09: f
|
||||
0x22, // 0a: g
|
||||
0x23, // 0b: h
|
||||
0x17, // 0c: i
|
||||
0x24, // 0d: j
|
||||
0x25, // 0e: k
|
||||
0x26, // 0f: l
|
||||
0x32, // 10: m
|
||||
0x31, // 11: n
|
||||
0x18, // 12: o
|
||||
0x19, // 13: p
|
||||
0x10, // 14: q
|
||||
0x13, // 15: r
|
||||
0x1f, // 16: s
|
||||
0x14, // 17: t
|
||||
0x16, // 18: u
|
||||
0x2f, // 19: v
|
||||
0x11, // 1a: w
|
||||
0x2d, // 1b: x
|
||||
0x15, // 1c: y
|
||||
0x2c, // 1d: z
|
||||
0x02, // 1e: 1
|
||||
0x03, // 1f: 2
|
||||
0x04, // 20: 3
|
||||
0x05, // 21: 4
|
||||
0x06, // 22: 5
|
||||
0x07, // 23: 6
|
||||
0x08, // 24: 7
|
||||
0x09, // 25: 8
|
||||
0x0a, // 26: 9
|
||||
0x0b, // 27: 0
|
||||
0x1c | OSD_LOC, // 28: Return
|
||||
0x01 | OSD_LOC, // 29: Escape
|
||||
0x0e, // 2a: Backspace
|
||||
0x0f, // 2b: Tab
|
||||
0x39 | OSD_LOC, // 2c: Space
|
||||
0x0c, // 2d: -
|
||||
0x0d, // 2e: =
|
||||
0x1a, // 2f: [
|
||||
0x1b, // 30: ]
|
||||
0x2b, // 31: backslash
|
||||
MISS, // 32: Europe 1
|
||||
0x27, // 33: ;
|
||||
0x28, // 34: '
|
||||
0x29, // 35: `
|
||||
0x33, // 36: ,
|
||||
0x34, // 37: .
|
||||
0x35, // 38: /
|
||||
0x3a | CAPS_LOCK_TOGGLE, // 39: Caps Lock
|
||||
0x3b, // 3a: F1
|
||||
0x3c, // 3b: F2
|
||||
0x3d, // 3c: F3
|
||||
0x3e, // 3d: F4
|
||||
0x3f, // 3e: F5
|
||||
0x40, // 3f: F6
|
||||
0x41, // 40: F7
|
||||
0x42, // 41: F8
|
||||
0x43, // 42: F9
|
||||
0x44, // 43: F10
|
||||
MISS, // 44: F11
|
||||
OSD_LOC, // 45: F12
|
||||
MISS, // 46: Print Screen
|
||||
MISS, // 47: Scroll Lock
|
||||
MISS, // 48: Pause
|
||||
0x52, // 49: Insert
|
||||
0x47, // 4a: Home
|
||||
0x62, // 4b: Page Up
|
||||
0x53, // 4c: Delete
|
||||
MISS, // 4d: End
|
||||
0x61, // 4e: Page Down
|
||||
0x4d, // 4f: Right Arrow
|
||||
0x4b, // 50: Left Arrow
|
||||
0x50 | OSD_LOC, // 51: Down Arrow
|
||||
0x48 | OSD_LOC, // 52: Up Arrow
|
||||
NUM_LOCK_TOGGLE, // 53: Num Lock
|
||||
0x65, // 54: KP /
|
||||
0x66, // 55: KP *
|
||||
0x4a, // 56: KP -
|
||||
0x4e, // 57: KP +
|
||||
0x72, // 58: KP Enter
|
||||
0x6d, // 59: KP 1
|
||||
0x6e, // 5a: KP 2
|
||||
0x6f, // 5b: KP 3
|
||||
0x6a, // 5c: KP 4
|
||||
0x6b, // 5d: KP 5
|
||||
0x6c, // 5e: KP 6
|
||||
0x67, // 5f: KP 7
|
||||
0x68, // 60: KP 8
|
||||
0x69, // 61: KP 9
|
||||
0x70, // 62: KP 0
|
||||
0x71, // 63: KP .
|
||||
0x60, // 64: Europe 2
|
||||
MISS, // 65: App
|
||||
MISS, // 66: Power
|
||||
MISS, // 67: KP =
|
||||
MISS, // 68: F13
|
||||
MISS, // 69: F14
|
||||
MISS, // 6a: F15
|
||||
MISS, // 6b: F16
|
||||
MISS, // 6c: F17
|
||||
MISS, // 6d: F18
|
||||
MISS, // 6e: F19
|
||||
MISS // 6f: F20
|
||||
};
|
||||
|
||||
// OSD uses amiga keycodes. This table translates from usb to OSD/amiga
|
||||
const unsigned char usb2osd[][2] = {
|
||||
{ 0x45, KEY_MENU },
|
||||
{ 0x52, KEY_UP },
|
||||
{ 0x51, KEY_DOWN },
|
||||
{ 0x28, KEY_ENTER },
|
||||
{ 0x29, KEY_ESC },
|
||||
{ 0x2c, KEY_SPACE },
|
||||
{ 0,0 }
|
||||
};
|
||||
|
||||
#if 0
|
||||
// #define KEY_UPSTROKE 0x80
|
||||
#define KEY_MENU 0x69
|
||||
#define KEY_PGUP 0x6C
|
||||
#define KEY_PGDN 0x6D
|
||||
#define KEY_HOME 0x6A
|
||||
#define KEY_ESC 0x45
|
||||
#define KEY_ENTER 0x44
|
||||
#define KEY_BACK 0x41
|
||||
#define KEY_SPACE 0x40
|
||||
#define KEY_UP 0x4C
|
||||
#define KEY_DOWN 0x4D
|
||||
#define KEY_LEFT 0x4F
|
||||
#define KEY_RIGHT 0x4E
|
||||
#define KEY_F1 0x50
|
||||
#define KEY_F2 0x51
|
||||
#define KEY_F3 0x52
|
||||
#define KEY_F4 0x53
|
||||
#define KEY_F5 0x54
|
||||
#define KEY_F6 0x55
|
||||
#define KEY_F7 0x56
|
||||
#define KEY_F8 0x57
|
||||
#define KEY_F9 0x58
|
||||
#define KEY_F10 0x59
|
||||
#define KEY_CTRL 0x63
|
||||
#define KEY_LALT 0x64
|
||||
#define KEY_KPPLUS 0x5E
|
||||
#define KEY_KPMINUS 0x4A
|
||||
#define KEY_KP0 0x0F
|
||||
#endif
|
||||
80
logo.h
Normal file
80
logo.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#ifndef LOGO_H
|
||||
#define LOGO_H
|
||||
const unsigned char logodata[5][227] = {
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0,
|
||||
0xc0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x83, 0x83, 0x83, 0x83, 0x83,
|
||||
0x83, 0x83, 0x83, 0x83, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x83, 0x83, 0x83, 0x83,
|
||||
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x83,
|
||||
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x00, 0x00, 0x80, 0x83, 0x87, 0x87, 0x8f, 0x8f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x0f,
|
||||
0x0f, 0x07, 0x07, 0x03, 0x00, 0x00, 0x00, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x83, 0x83,
|
||||
0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x03, 0x03, 0x03, 0x83,
|
||||
0x83, 0x03, 0x03},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xf0,
|
||||
0x7c, 0x1e, 0x07, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xc0, 0x00, 0x00, 0x00, 0x80,
|
||||
0x80, 0xc0, 0x60, 0x20, 0x30, 0x18, 0x8c, 0xc4, 0xf6, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f,
|
||||
0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe0, 0xf0, 0xfc, 0xff, 0xff, 0xff,
|
||||
0xff, 0x3f, 0x1f, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe0, 0xf0, 0x3c,
|
||||
0x0e, 0x07, 0x03, 0x07, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80,
|
||||
0x00, 0x00, 0x00, 0xc0, 0xf0, 0x38, 0x1e, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x80, 0xe0, 0xf0, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x1f, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x80, 0xc0, 0xf0, 0x7c, 0x1e, 0x07, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xfc, 0xc0, 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0x60, 0x20, 0x30, 0x18, 0x8c, 0xc4, 0xf6, 0xfb,
|
||||
0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
|
||||
0xc0, 0xf0, 0xf8, 0xfe, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xe0, 0xf0, 0xf8, 0xfc, 0xfc, 0xfe, 0xfe, 0xfe, 0x3e, 0x1f, 0x0f, 0x07, 0x07, 0x03, 0x03, 0x01,
|
||||
0x01, 0x41, 0x41, 0x40, 0x40, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, 0xc1, 0xc1, 0xc3, 0x47, 0x47, 0x43,
|
||||
0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x30, 0x30, 0x38, 0x3e, 0x2f, 0x23, 0x20,
|
||||
0x20, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x3f, 0x3f, 0x1f, 0x1f, 0x0f, 0x07, 0x06, 0x03, 0x21, 0x21,
|
||||
0x20, 0x20, 0x20, 0x30, 0x38, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x27, 0x21, 0x20, 0x00,
|
||||
0x00, 0x20, 0x20, 0x20, 0x20, 0x30, 0x38, 0x3c, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x27, 0x21,
|
||||
0x20, 0x20, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x30, 0x38, 0x3c, 0x3f, 0x27, 0x21, 0x20, 0x20,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f,
|
||||
0x3f, 0x1e, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x30, 0x38, 0x3c, 0x3f,
|
||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x27, 0x21, 0x20, 0x20, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x30,
|
||||
0x30, 0x38, 0x3e, 0x2f, 0x23, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x3f, 0x3f, 0x1f, 0x1f,
|
||||
0x0f, 0x07, 0x06, 0x03, 0x21, 0x21, 0x20, 0x20, 0x20, 0x30, 0x38, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||
0x3f, 0x3f, 0x27, 0x21, 0x20, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x38, 0x3e, 0x3f,
|
||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x27, 0x21, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x07, 0x0f, 0x0f, 0x1f, 0x1f, 0x1f, 0x3f, 0x38, 0x38, 0x30, 0x30, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x30, 0x38, 0x3c, 0x3f, 0x3f, 0x3f, 0x1f, 0x1f, 0x0f, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00},
|
||||
{0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18}
|
||||
};
|
||||
#endif
|
||||
240
main.c
Normal file
240
main.c
Normal file
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
Copyright 2005, 2006, 2007 Dennis van Weeren
|
||||
Copyright 2008, 2009 Jakub Bednarski
|
||||
Copyright 2012 Till Harbaum
|
||||
|
||||
This file is part of Minimig
|
||||
|
||||
Minimig is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Minimig is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// 2008-10-04 - porting to ARM
|
||||
// 2008-10-06 - support for 4 floppy drives
|
||||
// 2008-10-30 - hdd write support
|
||||
// 2009-05-01 - subdirectory support
|
||||
// 2009-06-26 - SDHC and FAT32 support
|
||||
// 2009-08-10 - hardfile selection
|
||||
// 2009-09-11 - minor changes to hardware initialization routine
|
||||
// 2009-10-10 - any length fpga core file support
|
||||
// 2009-11-14 - adapted floppy gap size
|
||||
// - changes to OSD labels
|
||||
// 2009-12-24 - updated version number
|
||||
// 2010-01-09 - changes to floppy handling
|
||||
// 2010-07-28 - improved menu button handling
|
||||
// - improved FPGA configuration routines
|
||||
// - added support for OSD vsync
|
||||
// 2010-08-15 - support for joystick emulation
|
||||
// 2010-08-18 - clean-up
|
||||
|
||||
#include "AT91SAM7S256.h"
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
#include "errors.h"
|
||||
#include "hardware.h"
|
||||
#include "mmc.h"
|
||||
#include "fat.h"
|
||||
#include "osd.h"
|
||||
#include "fpga.h"
|
||||
#include "fdd.h"
|
||||
#include "hdd.h"
|
||||
#include "firmware.h"
|
||||
#include "menu.h"
|
||||
#include "config.h"
|
||||
#include "user_io.h"
|
||||
#include "boot_logo.h"
|
||||
|
||||
#ifdef MIST
|
||||
#include "usb.h"
|
||||
#endif
|
||||
|
||||
const char version[] = {"$VER:ATH" VDATE};
|
||||
|
||||
extern hdfTYPE hdf[2];
|
||||
|
||||
unsigned char Error;
|
||||
extern adfTYPE df[4];
|
||||
char s[40];
|
||||
|
||||
void FatalError(unsigned long error)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
printf("Fatal error: %lu\r", error);
|
||||
|
||||
while (1)
|
||||
{
|
||||
for (i = 0; i < error; i++)
|
||||
{
|
||||
DISKLED_ON;
|
||||
WaitTimer(250);
|
||||
DISKLED_OFF;
|
||||
WaitTimer(250);
|
||||
}
|
||||
WaitTimer(1000);
|
||||
}
|
||||
}
|
||||
|
||||
void HandleFpga(void)
|
||||
{
|
||||
unsigned char c1, c2;
|
||||
|
||||
EnableFpga();
|
||||
c1 = SPI(0); // cmd request and drive number
|
||||
c2 = SPI(0); // track number
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
DisableFpga();
|
||||
|
||||
HandleFDD(c1, c2);
|
||||
HandleHDD(c1, c2);
|
||||
|
||||
UpdateDriveStatus();
|
||||
}
|
||||
|
||||
extern void inserttestfloppy();
|
||||
|
||||
int main(void)
|
||||
{
|
||||
unsigned char rc;
|
||||
unsigned char key;
|
||||
unsigned long time;
|
||||
unsigned short spiclk;
|
||||
//unsigned char CSD[16];
|
||||
|
||||
#ifdef __GNUC__
|
||||
__init_hardware();
|
||||
|
||||
// make sure printf works over rs232
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
#endif
|
||||
|
||||
DISKLED_ON;
|
||||
|
||||
Timer_Init();
|
||||
|
||||
USART_Init(115200);
|
||||
|
||||
printf("\rMinimig by Dennis van Weeren");
|
||||
printf("\rARM Controller by Jakub Bednarski\r\r");
|
||||
printf("Version %s\r\r", version+5);
|
||||
|
||||
SPI_Init();
|
||||
|
||||
if (!MMC_Init())
|
||||
FatalError(1);
|
||||
|
||||
spiclk = MCLK / ((AT91C_SPI_CSR[0] & AT91C_SPI_SCBR) >> 8) / 1000000;
|
||||
printf("spiclk: %u MHz\r", spiclk);
|
||||
|
||||
#ifdef USB_SEL
|
||||
usb_init();
|
||||
#endif
|
||||
|
||||
if (!FindDrive())
|
||||
FatalError(2);
|
||||
|
||||
ChangeDirectory(DIRECTORY_ROOT);
|
||||
|
||||
time = GetTimer(0);
|
||||
|
||||
user_io_init();
|
||||
|
||||
#ifdef MIST
|
||||
if(!user_io_button_pressed())
|
||||
#endif
|
||||
{
|
||||
if (ConfigureFpga()) {
|
||||
time = GetTimer(0) - time;
|
||||
printf("FPGA configured in %lu ms\r", time >> 20);
|
||||
} else {
|
||||
printf("FPGA configuration failed\r");
|
||||
FatalError(3);
|
||||
}
|
||||
|
||||
WaitTimer(100); // let's wait some time till reset is inactive so we can get a valid keycode
|
||||
}
|
||||
|
||||
user_io_detect_core_type();
|
||||
if(user_io_core_type() == CORE_TYPE_MINIMIG) {
|
||||
puts("Running minimig setup");
|
||||
|
||||
draw_boot_logo();
|
||||
BootPrintEx("**** MINIMIG for MiST ****");
|
||||
BootPrintEx("Minimig by Dennis van Weeren");
|
||||
BootPrintEx("Updates by Jakub Bednarski, Tobias Gubener, Sascha Boing, A.M. Robinson");
|
||||
BootPrintEx("DE1 port by Rok Krajnc (rok.krajnc@gmail.com)");
|
||||
BootPrintEx("MiST port by Till Harbaum (till@harbaum.org)");
|
||||
BootPrintEx(" ");
|
||||
BootPrintEx("For support, see http://www.minimig.net");
|
||||
BootPrint(" ");
|
||||
|
||||
ChangeDirectory(DIRECTORY_ROOT);
|
||||
|
||||
//eject all disk
|
||||
df[0].status = 0;
|
||||
df[1].status = 0;
|
||||
df[2].status = 0;
|
||||
df[3].status = 0;
|
||||
|
||||
BootPrint(" ");
|
||||
BootPrintEx("Booting ...");
|
||||
printf("Booting ...\r");
|
||||
|
||||
WaitTimer(6000);
|
||||
config.kickstart.name[0]=0;
|
||||
SetConfigurationFilename(0); // Use default config
|
||||
LoadConfiguration(0); // Use slot-based config filename
|
||||
|
||||
} // end of minimig setup
|
||||
|
||||
if(user_io_core_type() == CORE_TYPE_MIST) {
|
||||
puts("Running mist setup");
|
||||
|
||||
tos_upload();
|
||||
|
||||
// end of mist setup
|
||||
}
|
||||
|
||||
int cnt = 0;
|
||||
|
||||
while (1) {
|
||||
user_io_poll();
|
||||
|
||||
#ifdef USB_SEL
|
||||
usb_poll();
|
||||
#endif
|
||||
|
||||
// MIST (atari) core supports the same UI as Minimig
|
||||
if(user_io_core_type() == CORE_TYPE_MIST) {
|
||||
HandleUI();
|
||||
}
|
||||
|
||||
// call original minimig handlers if minimig core is found
|
||||
if(user_io_core_type() == CORE_TYPE_MINIMIG) {
|
||||
HandleFpga();
|
||||
HandleUI();
|
||||
|
||||
if(cnt < 20000) {
|
||||
cnt++;
|
||||
|
||||
if(cnt == 20000)
|
||||
inserttestfloppy();
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
96
menu.h
Normal file
96
menu.h
Normal file
@@ -0,0 +1,96 @@
|
||||
#ifndef MENU_H
|
||||
#define MENU_H
|
||||
|
||||
#include "fdd.h" // for adfTYPE definition
|
||||
|
||||
/*menu states*/
|
||||
enum MENU
|
||||
{
|
||||
MENU_NONE1,
|
||||
MENU_NONE2,
|
||||
MENU_MAIN1,
|
||||
MENU_MAIN2,
|
||||
MENU_MISC1,
|
||||
MENU_MISC2,
|
||||
MENU_ABOUT1,
|
||||
MENU_ABOUT2,
|
||||
MENU_FILE_SELECT1,
|
||||
MENU_FILE_SELECT2,
|
||||
MENU_FILE_SELECTED,
|
||||
MENU_RESET1,
|
||||
MENU_RESET2,
|
||||
MENU_RECONF1,
|
||||
MENU_RECONF2,
|
||||
MENU_SETTINGS1,
|
||||
MENU_SETTINGS2,
|
||||
MENU_ROMFILE_SELECTED,
|
||||
MENU_ROMFILE_SELECTED1,
|
||||
MENU_ROMFILE_SELECTED2,
|
||||
MENU_SETTINGS_VIDEO1,
|
||||
MENU_SETTINGS_VIDEO2,
|
||||
MENU_SETTINGS_MEMORY1,
|
||||
MENU_SETTINGS_MEMORY2,
|
||||
MENU_SETTINGS_CHIPSET1,
|
||||
MENU_SETTINGS_CHIPSET2,
|
||||
MENU_SETTINGS_DRIVES1,
|
||||
MENU_SETTINGS_DRIVES2,
|
||||
MENU_SETTINGS_HARDFILE1,
|
||||
MENU_SETTINGS_HARDFILE2,
|
||||
MENU_HARDFILE_SELECT1,
|
||||
MENU_HARDFILE_SELECT2,
|
||||
MENU_HARDFILE_SELECTED,
|
||||
MENU_HARDFILE_EXIT,
|
||||
MENU_HARDFILE_CHANGED1,
|
||||
MENU_HARDFILE_CHANGED2,
|
||||
MENU_SYNTHRDB1,
|
||||
MENU_SYNTHRDB2,
|
||||
MENU_SYNTHRDB2_1,
|
||||
MENU_SYNTHRDB2_2,
|
||||
MENU_MAIN2_1,
|
||||
MENU_MAIN2_2,
|
||||
MENU_LOADCONFIG_1,
|
||||
MENU_LOADCONFIG_2,
|
||||
MENU_SAVECONFIG_1,
|
||||
MENU_SAVECONFIG_2,
|
||||
MENU_FIRMWARE1,
|
||||
MENU_FIRMWARE2,
|
||||
MENU_FIRMWARE_UPDATE1,
|
||||
MENU_FIRMWARE_UPDATE2,
|
||||
MENU_FIRMWARE_UPDATE_ERROR1,
|
||||
MENU_FIRMWARE_UPDATE_ERROR2,
|
||||
MENU_FIRMWARE_UPDATING1,
|
||||
MENU_FIRMWARE_UPDATING2,
|
||||
MENU_FIRMWARE_OPTIONS1,
|
||||
MENU_FIRMWARE_OPTIONS2,
|
||||
MENU_FIRMWARE_OPTIONS_ENABLE1,
|
||||
MENU_FIRMWARE_OPTIONS_ENABLE2,
|
||||
MENU_FIRMWARE_OPTIONS_ENABLED1,
|
||||
MENU_FIRMWARE_OPTIONS_ENABLED2,
|
||||
MENU_ERROR,
|
||||
MENU_INFO,
|
||||
|
||||
// Mist/atari specifig pages
|
||||
MENU_MIST_MAIN1,
|
||||
MENU_MIST_MAIN2,
|
||||
MENU_MIST_FILE_SELECTED,
|
||||
};
|
||||
|
||||
// UI strings, used by boot messages
|
||||
extern const char *config_filter_msg[];
|
||||
extern const char *config_memory_chip_msg[];
|
||||
extern const char *config_memory_slow_msg[];
|
||||
extern const char *config_memory_fast_msg[];
|
||||
extern const char *config_scanline_msg[];
|
||||
|
||||
|
||||
void InsertFloppy(adfTYPE *drive);
|
||||
void HandleUI(void);
|
||||
void PrintDirectory(void);
|
||||
void ScrollLongName(void);
|
||||
void ErrorMessage(const char *message, unsigned char code);
|
||||
void InfoMessage(char *message);
|
||||
void ShowSplash();
|
||||
void HideSplash();
|
||||
|
||||
#endif
|
||||
|
||||
135
mkupg.c
Normal file
135
mkupg.c
Normal file
@@ -0,0 +1,135 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int flags;
|
||||
unsigned int base;
|
||||
unsigned int size;
|
||||
unsigned int crc;
|
||||
} __attribute__ ((packed)) romTYPE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char id[8];
|
||||
unsigned char version[16];
|
||||
romTYPE rom;
|
||||
unsigned int padding[117];
|
||||
unsigned int crc;
|
||||
} __attribute__ ((packed)) UPGRADE;
|
||||
|
||||
/* polynomial 0xEDB88320 */
|
||||
const unsigned int crc32_table[256] =
|
||||
{
|
||||
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
||||
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
||||
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
||||
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
||||
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
||||
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
||||
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
||||
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
||||
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
||||
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
||||
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
||||
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
||||
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
||||
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
||||
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
||||
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
||||
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
||||
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
||||
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
||||
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
||||
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
||||
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
||||
};
|
||||
|
||||
// Initial CRC value is -1 (0xFFFFFFFF)
|
||||
// Final CRC value is bitwise negation of the last calculated value
|
||||
unsigned int CalculateCRC32(unsigned int crc, unsigned char *pBuffer, unsigned int nSize)
|
||||
{
|
||||
while (nSize--)
|
||||
crc = crc32_table[(unsigned char)crc ^ *pBuffer++] ^ crc >> 8;
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
UPGRADE upgrade;
|
||||
|
||||
printf("mkupg - minimig/mist upgrade file creator\n");
|
||||
|
||||
if(argc != 4) {
|
||||
printf("Usage: mkupg <infile>.bin <outfile>.upg> <6-digit date code>\n");
|
||||
return -1;
|
||||
}
|
||||
if(strlen(argv[3])!=6)
|
||||
{
|
||||
printf("Date code should be a 6-digit code in the form YYMMDD\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
FILE *inf, *outf;
|
||||
int size;
|
||||
inf = fopen(argv[1], "rb");
|
||||
if(!inf) {
|
||||
printf("Unable to open %s\n", argv[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check file size
|
||||
fseek(inf, 0, SEEK_END);
|
||||
size = ftell(inf);
|
||||
fseek(inf, 0, SEEK_SET);
|
||||
|
||||
unsigned char *bin = malloc(size);
|
||||
if(fread(bin, 1, size, inf) != size) {
|
||||
printf("Read error on %s\n", argv[1]);
|
||||
return -1;
|
||||
}
|
||||
fclose(inf);
|
||||
|
||||
|
||||
printf("Upgrade header size : %u\n", (unsigned int)sizeof(UPGRADE));
|
||||
|
||||
// create upgrade header
|
||||
memset(&upgrade, 0, sizeof(upgrade));
|
||||
strcpy(upgrade.version,"ATH");
|
||||
strncpy(upgrade.version+3,argv[3],6);
|
||||
strcpy(upgrade.id, "MNMGUPG");
|
||||
upgrade.rom.size = size;
|
||||
upgrade.rom.crc = ~CalculateCRC32(-1, bin, size);
|
||||
upgrade.rom.size = size;
|
||||
|
||||
printf("ROM size : %d\n", size);
|
||||
printf("ROM CRC : %08X\n", upgrade.rom.crc);
|
||||
|
||||
upgrade.crc = ~CalculateCRC32(-1, (unsigned char*)&upgrade, sizeof(UPGRADE) - 4);
|
||||
printf("Header CRC : %08X\n", upgrade.crc);
|
||||
printf("Version string : %s\n", upgrade.version);
|
||||
|
||||
outf = fopen(argv[2], "wb");
|
||||
if(!outf) {
|
||||
printf("Unable to open %s for writing\n", argv[2]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fwrite(&upgrade, 1, sizeof(UPGRADE), outf);
|
||||
fwrite(bin, 1, size, outf);
|
||||
|
||||
fclose(outf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
567
mmc.c
Normal file
567
mmc.c
Normal file
@@ -0,0 +1,567 @@
|
||||
/*
|
||||
Copyright 2005, 2006, 2007 Dennis van Weeren
|
||||
Copyright 2008, 2009 Jakub Bednarski
|
||||
|
||||
This file is part of Minimig
|
||||
|
||||
Minimig is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Minimig is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// --== based on the work by Dennis van Weeren and Jan Derogee ==--
|
||||
// 2008-10-03 - adaptation for ARM controller
|
||||
// 2009-07-23 - clean-up and some optimizations
|
||||
// 2009-11-22 - multiple sector read implemented
|
||||
|
||||
|
||||
// FIXME - get capacity from SD card
|
||||
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
#include "hardware.h"
|
||||
|
||||
#include "mmc.h"
|
||||
#include "fat.h"
|
||||
|
||||
// variables
|
||||
unsigned char crc;
|
||||
unsigned long timeout;
|
||||
unsigned char response;
|
||||
unsigned char CardType;
|
||||
|
||||
unsigned char CSDData[16];
|
||||
|
||||
// internal functions
|
||||
static void MMC_CRC(unsigned char c) RAMFUNC;
|
||||
static unsigned char MMC_Command(unsigned char cmd, unsigned long arg) RAMFUNC;
|
||||
static unsigned char MMC_CMD12(void);
|
||||
|
||||
|
||||
// init memory card
|
||||
unsigned char MMC_Init(void)
|
||||
{
|
||||
unsigned char n;
|
||||
unsigned char ocr[4];
|
||||
|
||||
SPI_slow(); // set slow clock
|
||||
DisableCard(); // CS = 1
|
||||
SPI(0xff); // DI = 1
|
||||
TIMER_wait(20); // 20ms delay
|
||||
for (n=0; n<10; n++) SPI(0xff); // 80 dummy clocks, DI = 1
|
||||
TIMER_wait(20); // 20ms delay
|
||||
EnableCard();
|
||||
|
||||
CardType = CARDTYPE_NONE;
|
||||
|
||||
for(n=0; n<16; n++) {
|
||||
TIMER_wait(1);
|
||||
if (MMC_Command(CMD0, 0) == 0x01) break; // try to send CMD0 multiple times
|
||||
}
|
||||
if (n<16) // got CMD0 IDLE response
|
||||
{ // idle state
|
||||
timeout = GetTimer(1000); // initialization timeout 1s, 4s doesn't work with the original arm timer
|
||||
if (MMC_Command(CMD8, 0x1AA) == 0x01) // check if the card can operate with 2.7-3.6V power
|
||||
{ // SDHC card
|
||||
for (n = 0; n < 4; n++)
|
||||
ocr[n] = SPI(0xFF); // get the rest of R7 response
|
||||
if (ocr[2] == 0x01 && ocr[3] == 0xAA)
|
||||
{ // the card can work at 2.7-3.6V
|
||||
printf("SDHC card detected\r");
|
||||
while (!CheckTimer(timeout))
|
||||
{ // now we must wait until CMD41 returns 0 (or timeout elapses)
|
||||
if (MMC_Command(CMD55, 0) == 0x01)
|
||||
{ // CMD55 must precede any ACMD command
|
||||
if (MMC_Command(CMD41, 1 << 30) == 0x00) // ACMD41 with HCS bit
|
||||
{ // initialization completed
|
||||
if (MMC_Command(CMD58, 0) == 0x00)
|
||||
{ // check CCS (Card Capacity Status) bit in the OCR
|
||||
for (n = 0; n < 4; n++)
|
||||
ocr[n] = SPI(0xFF);
|
||||
|
||||
CardType = (ocr[0] & 0x40) ? CARDTYPE_SDHC : CARDTYPE_SD; // if CCS set then the card is SDHC compatible
|
||||
}
|
||||
else
|
||||
printf("CMD58 (READ_OCR) failed!\r");
|
||||
DisableCard();
|
||||
|
||||
// set appropriate SPI speed
|
||||
#ifdef ARM_FW
|
||||
if (GetSPIMode() == SPIMODE_FAST)
|
||||
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (2 << 8); // 24 MHz SPI clock (max 25 MHz for SDHC card)
|
||||
else
|
||||
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (6 << 8); // 8 MHz SPI clock (no SPI mod)
|
||||
#else
|
||||
SPI_fast();
|
||||
#endif
|
||||
return(CardType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("CMD55 (APP_CMD) failed!\r");
|
||||
DisableCard();
|
||||
return(CARDTYPE_NONE);
|
||||
}
|
||||
}
|
||||
printf("SDHC card initialization timed out!\r");
|
||||
DisableCard();
|
||||
return(CARDTYPE_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
// it's not an SDHC card
|
||||
if (MMC_Command(CMD55, 0) == 0x01)
|
||||
{ // CMD55 accepted so it's an SD card (or Kingston 128 MB MMC)
|
||||
if (MMC_Command(CMD41, 0) <= 0x01)
|
||||
{ // SD card detected - wait for the end of initialization
|
||||
printf("SD card detected\r");
|
||||
while (!CheckTimer(timeout))
|
||||
{ // now we must wait until CMD41 returns 0 (or timeout elapses)
|
||||
if (MMC_Command(CMD55, 0) == 0x01)
|
||||
{ // CMD55 must precede any ACMD command
|
||||
if (MMC_Command(CMD41, 0) == 0x00)
|
||||
{ // initialization completed
|
||||
|
||||
if (MMC_Command(CMD16, 512) != 0x00) //set block length
|
||||
printf("CMD16 (SET_BLOCKLEN) failed!\r");
|
||||
DisableCard();
|
||||
|
||||
// set appropriate SPI speed
|
||||
#ifdef ARM_FW
|
||||
if (GetSPIMode() == SPIMODE_FAST)
|
||||
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (2 << 8); // 24 MHz SPI clock (max 25 MHz for SD card)
|
||||
else
|
||||
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (6 << 8); // 8 MHz SPI clock (no SPI mod)
|
||||
CardType = CARDTYPE_SD;
|
||||
#else
|
||||
SPI_fast();
|
||||
CardType = CARDTYPE_SD;
|
||||
#endif
|
||||
return(CardType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("CMD55 (APP_CMD) failed!\r");
|
||||
DisableCard();
|
||||
return(CARDTYPE_NONE);
|
||||
}
|
||||
}
|
||||
printf("SD card initialization timed out!\r");
|
||||
DisableCard();
|
||||
return(CARDTYPE_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
// it's not an SD card
|
||||
printf("MMC card detected\r");
|
||||
while (!CheckTimer(timeout))
|
||||
{ // now we must wait until CMD1 returns 0 (or timeout elapses)
|
||||
if (MMC_Command(CMD1, 0) == 0x00)
|
||||
{ // initialization completed
|
||||
|
||||
if (MMC_Command(CMD16, 512) != 0x00) // set block length
|
||||
printf("CMD16 (SET_BLOCKLEN) failed!\r");
|
||||
|
||||
DisableCard();
|
||||
|
||||
// set appropriate SPI speed
|
||||
#ifdef ARM_FW
|
||||
if (GetSPIMode() == SPIMODE_FAST)
|
||||
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (3 << 8); // 16 MHz SPI clock (max 20 MHz for MMC card)
|
||||
else
|
||||
AT91C_SPI_CSR[0] = AT91C_SPI_CPOL | (6 << 8); // 8 MHz SPI clock (no SPI mod)
|
||||
#else
|
||||
SPI_fast_mmc();
|
||||
#endif
|
||||
CardType = CARDTYPE_MMC;
|
||||
|
||||
return(CardType);
|
||||
}
|
||||
}
|
||||
|
||||
printf("MMC card initialization timed out!\r");
|
||||
DisableCard();
|
||||
return(CARDTYPE_NONE);
|
||||
}
|
||||
|
||||
DisableCard();
|
||||
printf("No memory card detected!\r");
|
||||
return(CARDTYPE_NONE);
|
||||
}
|
||||
|
||||
|
||||
// Read single 512-byte block
|
||||
RAMFUNC unsigned char MMC_Read(unsigned long lba, unsigned char *pReadBuffer)
|
||||
{
|
||||
// if pReadBuffer is NULL then use direct to the FPGA transfer mode (FPGA2 asserted)
|
||||
|
||||
unsigned long i;
|
||||
unsigned char *p;
|
||||
|
||||
if (CardType != CARDTYPE_SDHC) // SDHC cards are addressed in sectors not bytes
|
||||
lba = lba << 9; // otherwise convert sector adddress to byte address
|
||||
|
||||
EnableCard();
|
||||
|
||||
if (MMC_Command(CMD17, lba))
|
||||
{
|
||||
// printf("CMD17 (READ_BLOCK): invalid response 0x%02X (lba=%lu)\r", response, lba);
|
||||
DisableCard();
|
||||
return(0);
|
||||
}
|
||||
|
||||
// now we are waiting for data token, it takes around 300us
|
||||
timeout = 0;
|
||||
while ((SPI(0xFF)) != 0xFE)
|
||||
{
|
||||
if (timeout++ >= 1000000) // we can't wait forever
|
||||
{
|
||||
// printf("CMD17 (READ_BLOCK): no data token! (lba=%lu)\r", lba);
|
||||
DisableCard();
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (pReadBuffer == 0)
|
||||
{ // in this mode we do not receive data, instead the FPGA captures directly the data stream transmitted by the SD/MMC card
|
||||
EnableDMode();
|
||||
SPI_block(511);
|
||||
SPI(0xff); // dummy write for 4096 clocks
|
||||
SPI(0xff);
|
||||
DisableDMode();
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef SPI_BLOCK_READ
|
||||
SPI_block_read(pReadBuffer);
|
||||
#else
|
||||
p=pReadBuffer;
|
||||
for (i = 0; i < 128; i++)
|
||||
{
|
||||
*(p++) = SPI(0xFF);
|
||||
*(p++) = SPI(0xFF);
|
||||
*(p++) = SPI(0xFF);
|
||||
*(p++) = SPI(0xFF);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SPI(0xFF); // read CRC lo byte
|
||||
SPI(0xFF); // read CRC hi byte
|
||||
|
||||
DisableCard();
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
// Read CSD register
|
||||
unsigned char MMC_GetCSD()
|
||||
{
|
||||
int i;
|
||||
EnableCard();
|
||||
|
||||
if (MMC_Command(CMD9,0))
|
||||
{
|
||||
printf("CMD9 (GET_CSD): invalid response 0x%02X \r", response);
|
||||
DisableCard();
|
||||
return(0);
|
||||
}
|
||||
|
||||
// now we are waiting for data token, it takes around 300us
|
||||
timeout = 0;
|
||||
while ((SPI(0xFF)) != 0xFE)
|
||||
{
|
||||
if (timeout++ >= 1000000) // we can't wait forever
|
||||
{
|
||||
printf("CMD9 (READ_BLOCK): no data token!\r");
|
||||
DisableCard();
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
CSDData[i]=SPI(0xFF);
|
||||
|
||||
SPI(0xFF); // read CRC lo byte
|
||||
SPI(0xFF); // read CRC hi byte
|
||||
|
||||
DisableCard();
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
// MMC get capacity
|
||||
unsigned long MMC_GetCapacity()
|
||||
{
|
||||
unsigned long result=0;
|
||||
MMC_GetCSD();
|
||||
// switch(CardType)
|
||||
// {
|
||||
// case CARDTYPE_SDHC:
|
||||
// result=(CSDData[7]&0x3f)<<26;
|
||||
// result|=CSDData[8]<<18;
|
||||
// result|=CSDData[9]<<10;
|
||||
// result+=1024;
|
||||
// return(result);
|
||||
// break;
|
||||
// default:
|
||||
// int blocksize=CSDData[5]&15; // READ_BL_LEN
|
||||
// blocksize=1<<(blocksize-9); // Now a scalar: physical block size / 512.
|
||||
// result=(CSDData[6]&3)<<10;
|
||||
// result|=CSDData[7]<<2;
|
||||
// result|=(CSDData[8]>>6)&3; // result now contains C_SIZE
|
||||
// int cmult=(CSDData[9]&3)<<1;
|
||||
// cmult|=(CSDData[10]>>7) & 1;
|
||||
// ++result;
|
||||
// result<<=cmult+2;
|
||||
// return(result);
|
||||
// break;
|
||||
// }
|
||||
if ((CSDData[0] & 0xC0)==0x40) //CSD Version 2.0 - SDHC
|
||||
{
|
||||
result=(CSDData[7]&0x3f)<<26;
|
||||
result|=CSDData[8]<<18;
|
||||
result|=CSDData[9]<<10;
|
||||
result+=1024;
|
||||
return(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
int blocksize=CSDData[5]&15; // READ_BL_LEN
|
||||
blocksize=1<<(blocksize-9); // Now a scalar: physical block size / 512.
|
||||
result=(CSDData[6]&3)<<10;
|
||||
result|=CSDData[7]<<2;
|
||||
result|=(CSDData[8]>>6)&3; // result now contains C_SIZE
|
||||
int cmult=(CSDData[9]&3)<<1;
|
||||
cmult|=(CSDData[10]>>7) & 1;
|
||||
++result;
|
||||
result<<=cmult+2;
|
||||
return(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// read multiple 512-byte blocks
|
||||
unsigned char MMC_ReadMultiple(unsigned long lba, unsigned char *pReadBuffer, unsigned long nBlockCount)
|
||||
{
|
||||
// if pReadBuffer is NULL then use direct to the FPGA transfer mode (FPGA2 asserted)
|
||||
|
||||
unsigned long i;
|
||||
unsigned char *p;
|
||||
|
||||
if (CardType != CARDTYPE_SDHC) // SDHC cards are addressed in sectors not bytes
|
||||
lba = lba << 9; // otherwise convert sector adddress to byte address
|
||||
EnableCard();
|
||||
|
||||
if (MMC_Command(CMD18, lba))
|
||||
{
|
||||
printf("CMD18 (READ_MULTIPLE_BLOCK): invalid response 0x%02X (lba=%u)\r", response, lba);
|
||||
DisableCard();
|
||||
return(0);
|
||||
}
|
||||
|
||||
while (nBlockCount--)
|
||||
{
|
||||
// now we are waiting for data token, it takes around 300us
|
||||
timeout = 0;
|
||||
while ((SPI(0xFF)) != 0xFE)
|
||||
{
|
||||
if (timeout++ >= 1000000) // we can't wait forever
|
||||
{
|
||||
printf("CMD18 (READ_MULTIPLE_BLOCK): no data token! (lba=%u)\r", lba);
|
||||
DisableCard();
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (pReadBuffer == 0)
|
||||
{ // in this mode we do not receive data, instead the FPGA captures directly the data stream transmitted by the SD/MMC card
|
||||
EnableDMode();
|
||||
SPI_block(511);
|
||||
SPI(0xff); // dummy write for 4096 clocks
|
||||
SPI(0xff);
|
||||
DisableDMode();
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef SPI_BLOCK_READ
|
||||
SPI_block_read(pReadBuffer);
|
||||
#else
|
||||
p=pReadBuffer;
|
||||
for (i = 0; i < 128; i++)
|
||||
{
|
||||
*(p++) = SPI(0xFF);
|
||||
*(p++) = SPI(0xFF);
|
||||
*(p++) = SPI(0xFF);
|
||||
*(p++) = SPI(0xFF);
|
||||
}
|
||||
#endif
|
||||
|
||||
pReadBuffer += 512; // point to next sector
|
||||
}
|
||||
|
||||
SPI(0xFF); // read CRC lo byte
|
||||
SPI(0xFF); // read CRC hi byte
|
||||
}
|
||||
|
||||
MMC_CMD12(); // stop multi block transmission
|
||||
|
||||
DisableCard();
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
// write 512-byte block
|
||||
unsigned char MMC_Write(unsigned long lba, unsigned char *pWriteBuffer)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
if (CardType != CARDTYPE_SDHC) // SDHC cards are addressed in sectors not bytes
|
||||
lba = lba << 9; // otherwise convert sector adddress to byte address
|
||||
|
||||
EnableCard();
|
||||
|
||||
if (MMC_Command(CMD24, lba))
|
||||
{
|
||||
printf("CMD24 (WRITE_BLOCK): invalid response 0x%02X (lba=%lu)\r", response, lba);
|
||||
DisableCard();
|
||||
return(0);
|
||||
}
|
||||
|
||||
SPI(0xFF); // one byte gap
|
||||
SPI(0xFE); // send Data Token
|
||||
|
||||
// send sector bytes
|
||||
for (i = 0; i < 512; i++)
|
||||
SPI(*(pWriteBuffer++));
|
||||
|
||||
SPI(0xFF); // send CRC lo byte
|
||||
SPI(0xFF); // send CRC hi byte
|
||||
|
||||
response = SPI(0xFF); // read packet response
|
||||
// Status codes
|
||||
// 010 = Data accepted
|
||||
// 101 = Data rejected due to CRC error
|
||||
// 110 = Data rejected due to write error
|
||||
response &= 0x1F;
|
||||
if (response != 0x05)
|
||||
{
|
||||
printf("CMD24 (WRITE_BLOCK): invalid status 0x%02X (lba=%lu)\r", response, lba);
|
||||
DisableCard();
|
||||
return(0);
|
||||
}
|
||||
|
||||
timeout = 0;
|
||||
while ((SPI(0xFF)) == 0x00) // wait until the card is not busy
|
||||
{
|
||||
if (timeout++ >= 1000000)
|
||||
{
|
||||
printf("CMD24 (WRITE_BLOCK): busy wait timeout! (lba=%lu)\r", lba);
|
||||
DisableCard();
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
DisableCard();
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
// MMC command
|
||||
static RAMFUNC unsigned char MMC_Command(unsigned char cmd, unsigned long arg)
|
||||
{
|
||||
unsigned char c;
|
||||
|
||||
crc = 0;
|
||||
SPI(0xFF); // flush SPI-bus
|
||||
|
||||
SPI(cmd);
|
||||
MMC_CRC(cmd);
|
||||
|
||||
c = (unsigned char)(arg >> 24);
|
||||
SPI(c);
|
||||
MMC_CRC(c);
|
||||
|
||||
c = (unsigned char)(arg >> 16);
|
||||
SPI(c);
|
||||
MMC_CRC(c);
|
||||
|
||||
c = (unsigned char)(arg >> 8);
|
||||
SPI(c);
|
||||
MMC_CRC(c);
|
||||
|
||||
c = (unsigned char)(arg);
|
||||
SPI(c);
|
||||
MMC_CRC(c);
|
||||
|
||||
crc <<= 1;
|
||||
crc++;
|
||||
SPI(crc);
|
||||
|
||||
unsigned char Ncr = 100; // Ncr = 0..8 (SD) / 1..8 (MMC)
|
||||
do
|
||||
response = SPI(0xFF); // get response
|
||||
while (response == 0xFF && Ncr--);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
// stop multi block data transmission
|
||||
static unsigned char MMC_CMD12(void)
|
||||
{
|
||||
SPI(CMD12); // command
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
SPI(0x00); // dummy CRC7
|
||||
SPI(0xFF); // skip stuff byte
|
||||
|
||||
unsigned char Ncr = 100; // Ncr = 0..8 (SD) / 1..8 (MMC)
|
||||
do
|
||||
{ response = SPI(0xFF); // get response
|
||||
// RS232(response);
|
||||
} while (response == 0xFF && Ncr--);
|
||||
|
||||
timeout = 0;
|
||||
while ((SPI(0xFF)) == 0x00) // wait until the card is not busy
|
||||
{ // RS232('+');
|
||||
if (timeout++ >= 1000000)
|
||||
{
|
||||
printf("CMD12 (STOP_TRANSMISSION): busy wait timeout!\r");
|
||||
DisableCard();
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
// MMC CRC calc
|
||||
static RAMFUNC void MMC_CRC(unsigned char c)
|
||||
{
|
||||
unsigned char i;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
crc <<= 1;
|
||||
if (c & 0x80)
|
||||
crc ^= 0x09;
|
||||
if (crc & 0x80)
|
||||
crc ^= 0x09;
|
||||
c <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
87
mmc.h
Normal file
87
mmc.h
Normal file
@@ -0,0 +1,87 @@
|
||||
#ifndef MMC_H
|
||||
#define MMC_H
|
||||
|
||||
#include "hardware.h"
|
||||
|
||||
#define CARDTYPE_NONE 0
|
||||
#define CARDTYPE_MMC 1
|
||||
#define CARDTYPE_SD 2
|
||||
#define CARDTYPE_SDHC 3
|
||||
|
||||
// MMC commandset
|
||||
#define CMD0 0x40 /*Resets the multimedia card*/
|
||||
#define CMD1 0x41 /*Activates the card's initialization process*/
|
||||
#define CMD2 0x42 /*--*/
|
||||
#define CMD3 0x43 /*--*/
|
||||
#define CMD4 0x44 /*--*/
|
||||
#define CMD5 0x45 /*reseved*/
|
||||
#define CMD6 0x46 /*reserved*/
|
||||
#define CMD7 0x47 /*--*/
|
||||
#define CMD8 0x48 /*reserved*/
|
||||
#define CMD9 0x49 /*CSD : Ask the selected card to send its card specific data*/
|
||||
#define CMD10 0x4a /*CID : Ask the selected card to send its card identification*/
|
||||
#define CMD11 0x4b /*--*/
|
||||
#define CMD12 0x4c /*--*/
|
||||
#define CMD13 0x4d /*Ask the selected card to send its status register*/
|
||||
#define CMD14 0x4e /*--*/
|
||||
#define CMD15 0x4f /*--*/
|
||||
#define CMD16 0x50 /*Select a block length (in bytes) for all following block commands (Read:between 1-512 and Write:only 512)*/
|
||||
#define CMD17 0x51 /*Reads a block of the size selected by the SET_BLOCKLEN command, the start address and block length must be set so that the data transferred will not cross a physical block boundry*/
|
||||
#define CMD18 0x52 /*--*/
|
||||
#define CMD19 0x53 /*reserved*/
|
||||
#define CMD20 0x54 /*--*/
|
||||
#define CMD21 0x55 /*reserved*/
|
||||
#define CMD22 0x56 /*reserved*/
|
||||
#define CMD23 0x57 /*reserved*/
|
||||
#define CMD24 0x58 /*Writes a block of the size selected by CMD16, the start address must be alligned on a sector boundry, the block length is always 512 bytes*/
|
||||
#define CMD25 0x59 /*--*/
|
||||
#define CMD26 0x5a /*--*/
|
||||
#define CMD27 0x5b /*Programming of the programmable bits of the CSD*/
|
||||
#define CMD28 0x5c /*If the card has write protection features, this command sets the write protection bit of the addressed group. The porperties of the write protection are coded in the card specific data (WP_GRP_SIZE)*/
|
||||
#define CMD29 0x5d /*If the card has write protection features, this command clears the write protection bit of the addressed group*/
|
||||
#define CMD30 0x5e /*If the card has write protection features, this command asks the card to send the status of the write protection bits. 32 write protection bits (representing 32 write protect groups starting at the specific address) followed by 16 CRD bits are transferred in a payload format via the data line*/
|
||||
#define CMD31 0x5f /*reserved*/
|
||||
#define CMD32 0x60 /*sets the address of the first sector of the erase group*/
|
||||
#define CMD33 0x61 /*Sets the address of the last sector in a cont. range within the selected erase group, or the address of a single sector to be selected for erase*/
|
||||
#define CMD34 0x62 /*Removes on previously selected sector from the erase selection*/
|
||||
#define CMD35 0x63 /*Sets the address of the first erase group within a range to be selected for erase*/
|
||||
#define CMD36 0x64 /*Sets the address of the last erase group within a continuos range to be selected for erase*/
|
||||
#define CMD37 0x65 /*Removes one previously selected erase group from the erase selection*/
|
||||
#define CMD38 0x66 /*Erases all previously selected sectors*/
|
||||
#define CMD39 0x67 /*--*/
|
||||
#define CMD40 0x68 /*--*/
|
||||
#define CMD41 0x69 /*reserved*/
|
||||
#define CMD42 0x6a /*reserved*/
|
||||
#define CMD43 0x6b /*reserved*/
|
||||
#define CMD44 0x6c /*reserved*/
|
||||
#define CMD45 0x6d /*reserved*/
|
||||
#define CMD46 0x6e /*reserved*/
|
||||
#define CMD47 0x6f /*reserved*/
|
||||
#define CMD48 0x70 /*reserved*/
|
||||
#define CMD49 0x71 /*reserved*/
|
||||
#define CMD50 0x72 /*reserved*/
|
||||
#define CMD51 0x73 /*reserved*/
|
||||
#define CMD52 0x74 /*reserved*/
|
||||
#define CMD53 0x75 /*reserved*/
|
||||
#define CMD54 0x76 /*reserved*/
|
||||
#define CMD55 0x77 /*reserved*/
|
||||
#define CMD56 0x78 /*reserved*/
|
||||
#define CMD57 0x79 /*reserved*/
|
||||
#define CMD58 0x7a /*reserved*/
|
||||
#define CMD59 0x7b /*Turns the CRC option ON or OFF. A '1' in the CRC option bit will turn the option ON, a '0' will turn it OFF*/
|
||||
#define CMD60 0x7c /*--*/
|
||||
#define CMD61 0x7d /*--*/
|
||||
#define CMD62 0x7e /*--*/
|
||||
#define CMD63 0x7f /*--*/
|
||||
|
||||
unsigned char MMC_Init(void);
|
||||
unsigned char MMC_Read(unsigned long lba, unsigned char *pReadBuffer) RAMFUNC;
|
||||
unsigned char MMC_Write(unsigned long lba, unsigned char *pWriteBuffer);
|
||||
unsigned char MMC_ReadMultiple(unsigned long lba, unsigned char *pReadBuffer, unsigned long nBlockCount);
|
||||
unsigned char MMC_GetCSD();
|
||||
unsigned long MMC_GetCapacity(); // Returns the capacity in 512 byte blocks
|
||||
|
||||
extern unsigned char CSDData[16];
|
||||
|
||||
#endif
|
||||
|
||||
870
osd.c
Normal file
870
osd.c
Normal file
@@ -0,0 +1,870 @@
|
||||
/*
|
||||
Copyright 2005, 2006, 2007 Dennis van Weeren
|
||||
Copyright 2008, 2009 Jakub Bednarski
|
||||
|
||||
This file is part of Minimig
|
||||
|
||||
Minimig is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Minimig is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
This is the Minimig OSD (on-screen-display) handler.
|
||||
|
||||
2012-02-09 - Split character rom out to separate header file, with upper 128 entries
|
||||
as rotated copies of the first 128 entries. -- AMR
|
||||
|
||||
29-12-2006 - created
|
||||
30-12-2006 - improved and simplified
|
||||
-- JB --
|
||||
2008-10-04 - ARM version
|
||||
2008-10-26 - added cpu and floppy configuration functions
|
||||
2008-12-31 - added enable HDD command
|
||||
2009-02-03 - full keyboard support
|
||||
2009-06-23 - hires OSD display
|
||||
2009-08-23 - adapted ConfigIDE() - support for 2 hardfiles
|
||||
*/
|
||||
|
||||
//#include "AT91SAM7S256.h"
|
||||
#include "osd.h"
|
||||
#include "hardware.h"
|
||||
#include "stdio.h"
|
||||
|
||||
#include "charrom.h"
|
||||
#include "logo.h"
|
||||
#include "user_io.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// conversion table of Amiga keyboard scan codes to ASCII codes
|
||||
const char keycode_table[128] =
|
||||
{
|
||||
0,'1','2','3','4','5','6','7','8','9','0', 0, 0, 0, 0, 0,
|
||||
'Q','W','E','R','T','Y','U','I','O','P', 0, 0, 0, 0, 0, 0,
|
||||
'A','S','D','F','G','H','J','K','L', 0, 0, 0, 0, 0, 0, 0,
|
||||
0,'Z','X','C','V','B','N','M', 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
struct star
|
||||
{
|
||||
int x, y;
|
||||
int dx, dy;
|
||||
};
|
||||
|
||||
struct star stars[64];
|
||||
|
||||
char framebuffer[8][256];
|
||||
void framebuffer_clear()
|
||||
{
|
||||
int i,j;
|
||||
for(i=0;i<8;++i)
|
||||
{
|
||||
for(j=0;j<256;++j)
|
||||
{
|
||||
framebuffer[i][j]=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void framebuffer_plot(int x,int y)
|
||||
{
|
||||
framebuffer[y/8][x]|=(1<<(y & 7));
|
||||
}
|
||||
|
||||
static int quickrand()
|
||||
{
|
||||
static int prev;
|
||||
#ifndef MIST
|
||||
int r=*(volatile unsigned long *)0x80000c;
|
||||
#else
|
||||
int r = (int)(AT91C_BASE_RTTC->RTTC_RTVR);
|
||||
#endif
|
||||
r^=(prev&0xc75a)<<4;
|
||||
r^=(prev&0x5a7c)>>(prev&7);
|
||||
prev=r;
|
||||
return(r);
|
||||
}
|
||||
|
||||
|
||||
void StarsInit()
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<64;++i)
|
||||
{
|
||||
stars[i].x=(quickrand()%228)<<4; // X centre
|
||||
stars[i].y=(quickrand()%56)<<4; // Y centre
|
||||
stars[i].dx=-(quickrand()&7)-3;
|
||||
stars[i].dy=0;
|
||||
}
|
||||
}
|
||||
|
||||
void StarsUpdate()
|
||||
{
|
||||
framebuffer_clear();
|
||||
int i;
|
||||
for(i=0;i<64;++i)
|
||||
{
|
||||
stars[i].x+=stars[i].dx;
|
||||
stars[i].y+=stars[i].dy;
|
||||
if((stars[i].x<0)||(stars[i].x>(228<<4)) ||
|
||||
(stars[i].y<0)||(stars[i].y>(56<<4)))
|
||||
{
|
||||
stars[i].x=228<<4;
|
||||
stars[i].y=(quickrand()%56)<<4;
|
||||
stars[i].dx=-(quickrand()&7)-3;
|
||||
stars[i].dy=0;
|
||||
}
|
||||
framebuffer_plot(stars[i].x>>4,stars[i].y>>4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// time delay after which file/dir name starts to scroll
|
||||
#define SCROLL_DELAY 1000
|
||||
#define SCROLL_DELAY2 50
|
||||
|
||||
static unsigned long scroll_offset=0; // file/dir name scrolling position
|
||||
static unsigned long scroll_timer=0; // file/dir name scrolling timer
|
||||
|
||||
extern char s[40];
|
||||
|
||||
static int arrow;
|
||||
static unsigned char titlebuffer[64];
|
||||
|
||||
static void rotatechar(unsigned char *in,unsigned char *out)
|
||||
{
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
for(b=0;b<8;++b)
|
||||
{
|
||||
a=0;
|
||||
for(c=0;c<8;++c)
|
||||
{
|
||||
a<<=1;
|
||||
a|=(in[c]>>b)&1;
|
||||
}
|
||||
out[b]=a;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OsdSetTitle(char *s,int a)
|
||||
{
|
||||
// Compose the title, condensing character gaps
|
||||
arrow=a;
|
||||
char zeros=0;
|
||||
char i=0,j=0;
|
||||
char outp=0;
|
||||
while(1)
|
||||
{
|
||||
int c=s[i++];
|
||||
if(c && (outp<64))
|
||||
{
|
||||
unsigned char *p = &charfont[c][0];
|
||||
for(j=0;j<8;++j)
|
||||
{
|
||||
unsigned char nc=*p++;
|
||||
if(nc)
|
||||
{
|
||||
zeros=0;
|
||||
titlebuffer[outp++]=nc;
|
||||
}
|
||||
else if(zeros==0)
|
||||
{
|
||||
titlebuffer[outp++]=0;
|
||||
zeros=1;
|
||||
}
|
||||
if(outp>63)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
for(i=outp;i<64;++i)
|
||||
{
|
||||
titlebuffer[i]=0;
|
||||
}
|
||||
|
||||
// Now centre it:
|
||||
int c=(63-outp)/2;
|
||||
for(i=(63-c);i>=0;--i)
|
||||
{
|
||||
titlebuffer[i+c]=titlebuffer[i];
|
||||
}
|
||||
for(i=0;i<c;++i)
|
||||
titlebuffer[i]=0;
|
||||
|
||||
// Finally rotate it.
|
||||
for(i=0;i<64;i+=8)
|
||||
{
|
||||
unsigned char tmp[8];
|
||||
rotatechar(&titlebuffer[i],tmp);
|
||||
for(c=0;c<8;++c)
|
||||
{
|
||||
titlebuffer[i+c]=tmp[c];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OsdWrite(unsigned char n, char *s, unsigned char invert, unsigned char stipple)
|
||||
{
|
||||
OsdWriteOffset(n,s,invert,stipple,0);
|
||||
}
|
||||
|
||||
// write a null-terminated string <s> to the OSD buffer starting at line <n>
|
||||
void OsdWriteOffset(unsigned char n, char *s, unsigned char invert, unsigned char stipple,char offset)
|
||||
{
|
||||
unsigned short i;
|
||||
unsigned char b;
|
||||
const unsigned char *p;
|
||||
unsigned char stipplemask=0xff;
|
||||
int linelimit=OSDLINELEN;
|
||||
int arrowmask=arrow;
|
||||
if(n==7 && (arrow & OSD_ARROW_RIGHT))
|
||||
linelimit-=22;
|
||||
|
||||
if(stipple)
|
||||
{
|
||||
stipplemask=0x55;
|
||||
stipple=0xff;
|
||||
}
|
||||
else
|
||||
stipple=0;
|
||||
|
||||
// select OSD SPI device
|
||||
EnableOsd();
|
||||
|
||||
// select buffer and line to write to
|
||||
// if (invert)
|
||||
// SPI(OSDCMDWRITE | 0x10 | n);
|
||||
// else
|
||||
SPI(OSDCMDWRITE | n);
|
||||
|
||||
if(invert)
|
||||
invert=255;
|
||||
|
||||
i = 0;
|
||||
// send all characters in string to OSD
|
||||
while (1)
|
||||
{
|
||||
if(i==0) // Render sidestripe
|
||||
{
|
||||
p = &titlebuffer[(7-n)*8];
|
||||
SPI(0xff);
|
||||
SPI(0xff);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(0xff);
|
||||
SPI(0xff);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
i += 22;
|
||||
}
|
||||
else if(n==7 && (arrowmask & OSD_ARROW_LEFT)) // Draw initial arrow
|
||||
{
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
p = &charfont[0x10][0];
|
||||
SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset);
|
||||
SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset);
|
||||
p = &charfont[0x14][0];
|
||||
SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset);
|
||||
SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
SPI(invert);
|
||||
SPI(invert);
|
||||
i+=24;
|
||||
arrowmask&=~OSD_ARROW_LEFT;
|
||||
if(*s++ == 0) break; // Skip 3 characters, to keep alignent the same.
|
||||
if(*s++ == 0) break;
|
||||
if(*s++ == 0) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
b = *s++;
|
||||
|
||||
if (b == 0) // end of string
|
||||
break;
|
||||
|
||||
else if (b == 0x0d || b == 0x0a) // cariage return / linefeed, go to next line
|
||||
{
|
||||
// increment line counter
|
||||
if (++n >= linelimit)
|
||||
n = 0;
|
||||
// send new line number to OSD
|
||||
DisableOsd();
|
||||
EnableOsd();
|
||||
SPI(OSDCMDWRITE | n);
|
||||
}
|
||||
else if(i<(linelimit-8)) // normal character
|
||||
{
|
||||
p = &charfont[b][0];
|
||||
SPI(((*p++<<offset)&stipplemask)^invert); stipplemask^=stipple;
|
||||
SPI(((*p++<<offset)&stipplemask)^invert); stipplemask^=stipple;
|
||||
SPI(((*p++<<offset)&stipplemask)^invert); stipplemask^=stipple;
|
||||
SPI(((*p++<<offset)&stipplemask)^invert); stipplemask^=stipple;
|
||||
SPI(((*p++<<offset)&stipplemask)^invert); stipplemask^=stipple;
|
||||
SPI(((*p++<<offset)&stipplemask)^invert); stipplemask^=stipple;
|
||||
SPI(((*p++<<offset)&stipplemask)^invert); stipplemask^=stipple;
|
||||
SPI(((*p++<<offset)&stipplemask)^invert); stipplemask^=stipple;
|
||||
i += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (; i < linelimit; i++) // clear end of line
|
||||
SPI(invert);
|
||||
if(n==7 && (arrowmask & OSD_ARROW_RIGHT)) // Draw final arrow if needed
|
||||
{
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
p = &charfont[0x15][0];
|
||||
SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset);
|
||||
SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset);
|
||||
p = &charfont[0x11][0];
|
||||
SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset);
|
||||
SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset); SPI(*p++<<offset);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
SPI(0);
|
||||
i+=22;
|
||||
}
|
||||
|
||||
// deselect OSD SPI device
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
|
||||
void OsdDrawLogo(unsigned char n, char row,char superimpose)
|
||||
{
|
||||
unsigned short i;
|
||||
const unsigned char *p;
|
||||
int linelimit=OSDLINELEN;
|
||||
|
||||
// select OSD SPI device
|
||||
EnableOsd();
|
||||
|
||||
// select buffer and line to write to
|
||||
SPI(OSDCMDWRITE | n);
|
||||
|
||||
const unsigned char *lp=logodata[row];
|
||||
int bytes=sizeof(logodata[0]);
|
||||
if(row>=(sizeof(logodata)/bytes))
|
||||
lp=0;
|
||||
i = 0;
|
||||
// send all characters in string to OSD
|
||||
|
||||
if(superimpose)
|
||||
{
|
||||
char *bg=framebuffer[n];
|
||||
while (bytes)
|
||||
{
|
||||
if(i==0) // Render sidestripe
|
||||
{
|
||||
p = &titlebuffer[(7-n)*8];
|
||||
SPI(0xff);
|
||||
SPI(0xff);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(0xff);
|
||||
SPI(0xff);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
i += 22;
|
||||
}
|
||||
if(i>=linelimit)
|
||||
break;
|
||||
if(lp)
|
||||
SPI(*lp++ | *bg++);
|
||||
else
|
||||
SPI(*bg++);
|
||||
--bytes;
|
||||
++i;
|
||||
}
|
||||
for (; i < linelimit; i++) // clear end of line
|
||||
SPI(*bg++);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (bytes)
|
||||
{
|
||||
if(i==0) // Render sidestripe
|
||||
{
|
||||
p = &titlebuffer[(7-n)*8];
|
||||
SPI(0xff);
|
||||
SPI(0xff);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(0xff);
|
||||
SPI(0xff);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
i += 22;
|
||||
}
|
||||
if(i>=linelimit)
|
||||
break;
|
||||
if(lp)
|
||||
SPI(*lp++);
|
||||
else
|
||||
SPI(0);
|
||||
--bytes;
|
||||
++i;
|
||||
}
|
||||
for (; i < linelimit; i++) // clear end of line
|
||||
SPI(0);
|
||||
}
|
||||
// deselect OSD SPI device
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
|
||||
void OsdWriteDoubleSize(unsigned char n, char *s, unsigned char pass)
|
||||
{
|
||||
unsigned short i;
|
||||
unsigned char b;
|
||||
const unsigned char *p;
|
||||
int linelimit=OSDLINELEN;
|
||||
|
||||
// select OSD SPI device
|
||||
EnableOsd();
|
||||
|
||||
// select buffer and line to write to
|
||||
SPI(OSDCMDWRITE | n);
|
||||
|
||||
i = 0;
|
||||
// send all characters in string to OSD
|
||||
while (1)
|
||||
{
|
||||
if(i==0) // Render sidestripe
|
||||
{
|
||||
p = &titlebuffer[(7-n)*8];
|
||||
SPI(0xff);
|
||||
SPI(0xff);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
SPI(0xff);
|
||||
SPI(0xff);
|
||||
SPI(0x00);
|
||||
SPI(0x00);
|
||||
i += 22;
|
||||
}
|
||||
else
|
||||
{
|
||||
b = *s++;
|
||||
|
||||
if (b == 0) // end of string
|
||||
break;
|
||||
|
||||
else if(i<(linelimit-16)) // normal character
|
||||
{
|
||||
int c;
|
||||
p = &charfont[b][0];
|
||||
if(pass) // Draw the bottom half..
|
||||
{
|
||||
int j;
|
||||
for(j=0;j<8;++j)
|
||||
{
|
||||
c=*p++;
|
||||
c=(c&0xf0)>>4;
|
||||
c=(c&0x08)<<1 | c; // ....ABCD => ...AABCD
|
||||
c=(c&0x1c)<<1 | (c & 0x07); // ...AABCD => ..AABBCD
|
||||
c=(c&0x3e)<<1 | (c & 0x03); // ..AABBCD => .AABBCCD
|
||||
c=c<<1 | (c&0x01); // .AABBCCD => AABBCCDD
|
||||
SPI(c); SPI(c);
|
||||
}
|
||||
}
|
||||
else // Draw the top half...
|
||||
{
|
||||
int j;
|
||||
for(j=0;j<8;++j)
|
||||
{
|
||||
c=*p++;
|
||||
c=c&0xf;
|
||||
c=(c&0x08)<<1 | c; // ....ABCD => ...AABCD
|
||||
c=(c&0x1c)<<1 | (c & 0x07); // ...AABCD => ..AABBCD
|
||||
c=(c&0x3e)<<1 | (c & 0x03); // ..AABBCD => .AABBCCD
|
||||
c=c<<1 | (c&0x01); // .AABBCCD => AABBCCDD
|
||||
SPI(c); SPI(c);
|
||||
}
|
||||
}
|
||||
i += 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (; i < linelimit; i++) // clear end of line
|
||||
SPI(0);
|
||||
|
||||
// deselect OSD SPI device
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
// write a null-terminated string <s> to the OSD buffer starting at line <n>
|
||||
void OSD_PrintText(unsigned char line, char *text, unsigned long start, unsigned long width, unsigned long offset, unsigned char invert)
|
||||
{
|
||||
// line : OSD line number (0-7)
|
||||
// text : pointer to null-terminated string
|
||||
// start : start position (in pixels)
|
||||
// width : printed text length in pixels
|
||||
// offset : scroll offset in pixels counting from the start of the string (0-7)
|
||||
// invert : invertion flag
|
||||
|
||||
const unsigned char *p;
|
||||
int i,j;
|
||||
|
||||
// select OSD SPI device
|
||||
EnableOsd();
|
||||
|
||||
// select buffer and line to write to
|
||||
// if (invert)
|
||||
// SPI(OSDCMDWRITE | 0x10 | line);
|
||||
// else
|
||||
SPI(OSDCMDWRITE | line);
|
||||
|
||||
if(invert)
|
||||
invert=0xff;
|
||||
|
||||
p = &titlebuffer[(7-line)*8];
|
||||
if(start>2)
|
||||
{
|
||||
SPI(0xff); SPI(0xff); start-=2;
|
||||
}
|
||||
|
||||
i=start>16 ? 16 : start;
|
||||
for(j=0;j<(i/2);++j)
|
||||
{
|
||||
SPI(255^*p); SPI(255^*p++);
|
||||
}
|
||||
if(i&1)
|
||||
SPI(255^*p);
|
||||
start-=i;
|
||||
|
||||
if(start>2)
|
||||
SPI(0xff), SPI(0xff), start-=2;
|
||||
|
||||
while (start--)
|
||||
SPI(0x00);
|
||||
|
||||
if (offset)
|
||||
{
|
||||
width -= 8 - offset;
|
||||
p = &charfont[*text++][offset];
|
||||
for (; offset < 8; offset++)
|
||||
SPI(*p++^invert);
|
||||
}
|
||||
|
||||
while (width > 8)
|
||||
{
|
||||
p = &charfont[*text++][0];
|
||||
SPI(*p++^invert);
|
||||
SPI(*p++^invert);
|
||||
SPI(*p++^invert);
|
||||
SPI(*p++^invert);
|
||||
SPI(*p++^invert);
|
||||
SPI(*p++^invert);
|
||||
SPI(*p++^invert);
|
||||
SPI(*p++^invert);
|
||||
width -= 8;
|
||||
}
|
||||
|
||||
if (width)
|
||||
{
|
||||
p = &charfont[*text++][0];
|
||||
while (width--)
|
||||
SPI(*p++^invert);
|
||||
}
|
||||
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
// clear OSD frame buffer
|
||||
void OsdClear(void)
|
||||
{
|
||||
unsigned short n;
|
||||
|
||||
// select OSD SPI device
|
||||
EnableOsd();
|
||||
|
||||
// select buffer to write to
|
||||
SPI(OSDCMDWRITE | 0x18);
|
||||
|
||||
// clear buffer
|
||||
for (n = 0; n < (OSDLINELEN * OSDNLINE); n++)
|
||||
SPI(0x00);
|
||||
|
||||
// deselect OSD SPI device
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
void OsdWaitVBL(void)
|
||||
{
|
||||
// unsigned long pioa_old = 0;
|
||||
// unsigned long pioa = 0;
|
||||
//
|
||||
// while ((~pioa ^ pioa_old) & INIT_B)
|
||||
// {
|
||||
// pioa_old = pioa;
|
||||
// pioa = *AT91C_PIOA_PDSR;
|
||||
// }
|
||||
}
|
||||
|
||||
// enable displaying of OSD
|
||||
void OsdEnable(unsigned char mode)
|
||||
{
|
||||
user_io_osd_key_enable(mode & DISABLE_KEYBOARD);
|
||||
|
||||
EnableOsd();
|
||||
SPI(OSDCMDENABLE | (mode & DISABLE_KEYBOARD));
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
// disable displaying of OSD
|
||||
void OsdDisable(void)
|
||||
{
|
||||
user_io_osd_key_enable(0);
|
||||
|
||||
EnableOsd();
|
||||
SPI(OSDCMDDISABLE);
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
void OsdReset(unsigned char boot)
|
||||
{
|
||||
EnableOsd();
|
||||
SPI(OSDCMDRST | (boot & 0x01));
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
void ConfigFilter(unsigned char lores, unsigned char hires)
|
||||
{
|
||||
EnableOsd();
|
||||
SPI(OSDCMDCFGFLT | ((hires & 0x03) << 2) | (lores & 0x03));
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
void ConfigMemory(unsigned char memory)
|
||||
{
|
||||
EnableOsd();
|
||||
SPI(OSDCMDCFGMEM | (memory & 0x03)); //chip
|
||||
DisableOsd();
|
||||
EnableOsd();
|
||||
SPI(OSDCMDCFGMEM | 0x04 | ((memory>>2) & 0x03)); //slow
|
||||
DisableOsd();
|
||||
EnableOsd();
|
||||
SPI(OSDCMDCFGMEM | 0x08 | ((memory>>4) & 0x03)); //fast
|
||||
DisableOsd();
|
||||
EnableOsd();
|
||||
// SPI(OSDCMDCFGCPU| 0x00); //68000 - Don't want to disable '020 here! AMR
|
||||
// DisableOsd();
|
||||
}
|
||||
|
||||
void ConfigCPU(unsigned char cpu)
|
||||
{
|
||||
EnableOsd();
|
||||
SPI(OSDCMDCFGCPU | (cpu & 0x03)); //CPU
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
void ConfigChipset(unsigned char chipset)
|
||||
{
|
||||
EnableOsd();
|
||||
SPI(OSDCMDCFGCHP | (chipset & 0x0F));
|
||||
// SPI(OSDCMDCFGCHP | (chipset & 0x0E));
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
void ConfigFloppy(unsigned char drives, unsigned char speed)
|
||||
{
|
||||
EnableOsd();
|
||||
SPI(OSDCMDCFGFLP | ((drives & 0x03) << 2) | (speed & 0x03));
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
void ConfigScanlines(unsigned char scanlines)
|
||||
{
|
||||
EnableOsd();
|
||||
SPI(OSDCMDCFGSCL | (scanlines & 0x0F));
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
void ConfigIDE(unsigned char gayle, unsigned char master, unsigned char slave)
|
||||
{
|
||||
EnableOsd();
|
||||
SPI(OSDCMDCFGIDE | (slave ? 4 : 0) | (master ? 2 : 0) | (gayle ? 1 : 0));
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
void ConfigAutofire(unsigned char autofire)
|
||||
{
|
||||
EnableOsd();
|
||||
SPI(OSDCMDAUTOFIRE | (autofire & 0x03));
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
// get key status
|
||||
unsigned char OsdGetCtrl(void)
|
||||
{
|
||||
static unsigned char c2;
|
||||
static unsigned long delay;
|
||||
static unsigned long repeat;
|
||||
static unsigned char repeat2;
|
||||
unsigned char c1,c;
|
||||
|
||||
// minimig OSD is controlled by key codes from core
|
||||
if(user_io_core_type() == CORE_TYPE_MINIMIG) {
|
||||
// send command and get current ctrl status
|
||||
EnableOsd();
|
||||
c1 = SPI(OSDCMDREAD);
|
||||
DisableOsd();
|
||||
}
|
||||
|
||||
// mist/atari core uses local queue
|
||||
if(user_io_core_type() == CORE_TYPE_MIST)
|
||||
c1 = OsdKeyGet();
|
||||
|
||||
// add front menu button
|
||||
if (!CheckButton())
|
||||
delay = GetTimer(BUTTONDELAY);
|
||||
else if (CheckTimer(delay))
|
||||
{
|
||||
c1 = KEY_MENU;
|
||||
delay = GetTimer(-1);
|
||||
}
|
||||
|
||||
// generate normal "key-pressed" event
|
||||
c = 0;
|
||||
if (c1 != c2)
|
||||
c = c1;
|
||||
|
||||
c2 = c1;
|
||||
|
||||
// generate repeat "key-pressed" events
|
||||
if (c1 & KEY_UPSTROKE)
|
||||
{
|
||||
repeat = GetTimer(REPEATDELAY);
|
||||
}
|
||||
else if (CheckTimer(repeat))
|
||||
{
|
||||
repeat = GetTimer(REPEATRATE);
|
||||
if (c1 == KEY_UP || c1 == KEY_DOWN)
|
||||
c = c1;
|
||||
repeat2++;
|
||||
if (repeat2 == 2)
|
||||
{
|
||||
repeat2 = 0;
|
||||
if (c1 == KEY_PGUP || c1 == KEY_PGDN || GetASCIIKey(c1))
|
||||
c = c1;
|
||||
}
|
||||
}
|
||||
|
||||
return(c);
|
||||
}
|
||||
|
||||
unsigned char GetASCIIKey(unsigned char keycode)
|
||||
{
|
||||
if (keycode & KEY_UPSTROKE)
|
||||
return 0;
|
||||
|
||||
return keycode_table[keycode & 0x7F];
|
||||
}
|
||||
|
||||
|
||||
void ScrollText(char n,const char *str, int len,int max_len,unsigned char invert)
|
||||
{
|
||||
// this function is called periodically when a string longer than the window is displayed.
|
||||
|
||||
#define BLANKSPACE 10 // number of spaces between the end and start of repeated name
|
||||
|
||||
long offset;
|
||||
if(!max_len)
|
||||
max_len=30;
|
||||
|
||||
if (str && str[0] && CheckTimer(scroll_timer)) // scroll if long name and timer delay elapsed
|
||||
{
|
||||
scroll_timer = GetTimer(SCROLL_DELAY2); // reset scroll timer to repeat delay
|
||||
|
||||
scroll_offset++; // increase scroll position (1 pixel unit)
|
||||
memset(s, ' ', 32); // clear buffer
|
||||
|
||||
if(!len)
|
||||
len = strlen(str); // get name length
|
||||
|
||||
if (len > max_len) // scroll name if longer than display size
|
||||
{
|
||||
if (scroll_offset >= (len + BLANKSPACE) << 3) // reset scroll position if it exceeds predefined maximum
|
||||
scroll_offset = 0;
|
||||
|
||||
offset = scroll_offset >> 3; // get new starting character of the name (scroll_offset is no longer in 2 pixel unit)
|
||||
|
||||
len -= offset; // remaining number of characters in the name
|
||||
|
||||
if(len>max_len)
|
||||
len=max_len;
|
||||
|
||||
if (len > 0)
|
||||
strncpy(s, &str[offset], len); // copy name substring
|
||||
|
||||
if (len < max_len - BLANKSPACE) // file name substring and blank space is shorter than display line size
|
||||
strncpy(s + len + BLANKSPACE, str, max_len - len - BLANKSPACE); // repeat the name after its end and predefined number of blank space
|
||||
|
||||
OSD_PrintText(n, s, 22, (max_len - 1) << 3, (scroll_offset & 0x7), invert); // OSD print function with pixel precision
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScrollReset()
|
||||
{
|
||||
scroll_timer = GetTimer(SCROLL_DELAY); // set timer to start name scrolling after predefined time delay
|
||||
scroll_offset = 0; // start scrolling from the start
|
||||
}
|
||||
|
||||
/* the Atari core handles OSD keys competely inside the core */
|
||||
static unsigned char osd_key;
|
||||
|
||||
void OsdKeySet(unsigned char c) {
|
||||
osd_key = c;
|
||||
}
|
||||
|
||||
unsigned char OsdKeyGet() {
|
||||
return osd_key;
|
||||
}
|
||||
111
osd.h
Normal file
111
osd.h
Normal file
@@ -0,0 +1,111 @@
|
||||
#ifndef OSD_H_INCLUDED
|
||||
#define OSD_H_INCLUDED
|
||||
|
||||
/*constants*/
|
||||
#define OSDCTRLUP 0x01 /*OSD up control*/
|
||||
#define OSDCTRLDOWN 0x02 /*OSD down control*/
|
||||
#define OSDCTRLSELECT 0x04 /*OSD select control*/
|
||||
#define OSDCTRLMENU 0x08 /*OSD menu control*/
|
||||
#define OSDCTRLRIGHT 0x10 /*OSD right control*/
|
||||
#define OSDCTRLLEFT 0x20 /*OSD left control*/
|
||||
|
||||
// some constants
|
||||
#define OSDNLINE 8 // number of lines of OSD
|
||||
#define OSDLINELEN 256 // single line length in bytes
|
||||
#define OSDCMDREAD 0x00 // OSD read controller/key status
|
||||
#define OSDCMDWRITE 0x20 // OSD write video data command
|
||||
#define OSDCMDENABLE 0x41 // OSD enable command
|
||||
#define OSDCMDDISABLE 0x40 // OSD disable command
|
||||
#define OSDCMDRST 0x80 // OSD reset command
|
||||
#define OSDCMDRECONFIG 0x82 // OSD reset command
|
||||
#define OSDCMDAUTOFIRE 0x84 // OSD autofire command
|
||||
#define OSDCMDCFGSCL 0xA0 // OSD settings: scanlines effect
|
||||
#define OSDCMDCFGIDE 0xB0 // OSD enable HDD command
|
||||
#define OSDCMDCFGFLP 0xC0 // OSD settings: floppy config
|
||||
#define OSDCMDCFGCHP 0xD0 // OSD settings: chipset config
|
||||
#define OSDCMDCFGFLT 0xE0 // OSD settings: filter
|
||||
#define OSDCMDCFGMEM 0xF0 // OSD settings: memory config
|
||||
#define OSDCMDCFGCPU 0xFC // OSD settings: CPU config
|
||||
|
||||
#define DISABLE_KEYBOARD 0x02 // disable keyboard while OSD is active
|
||||
|
||||
#define REPEATDELAY 500 // repeat delay in 1ms units
|
||||
#define REPEATRATE 50 // repeat rate in 1ms units
|
||||
#define BUTTONDELAY 20 // repeat rate in 1ms units
|
||||
|
||||
#define KEY_UPSTROKE 0x80
|
||||
#define KEY_MENU 0x69
|
||||
#define KEY_PGUP 0x6C
|
||||
#define KEY_PGDN 0x6D
|
||||
#define KEY_HOME 0x6A
|
||||
#define KEY_ESC 0x45
|
||||
#define KEY_ENTER 0x44
|
||||
#define KEY_BACK 0x41
|
||||
#define KEY_SPACE 0x40
|
||||
#define KEY_UP 0x4C
|
||||
#define KEY_DOWN 0x4D
|
||||
#define KEY_LEFT 0x4F
|
||||
#define KEY_RIGHT 0x4E
|
||||
#define KEY_F1 0x50
|
||||
#define KEY_F2 0x51
|
||||
#define KEY_F3 0x52
|
||||
#define KEY_F4 0x53
|
||||
#define KEY_F5 0x54
|
||||
#define KEY_F6 0x55
|
||||
#define KEY_F7 0x56
|
||||
#define KEY_F8 0x57
|
||||
#define KEY_F9 0x58
|
||||
#define KEY_F10 0x59
|
||||
#define KEY_CTRL 0x63
|
||||
#define KEY_LALT 0x64
|
||||
#define KEY_KPPLUS 0x5E
|
||||
#define KEY_KPMINUS 0x4A
|
||||
#define KEY_KP0 0x0F
|
||||
|
||||
#define CONFIG_TURBO 1
|
||||
#define CONFIG_NTSC 2
|
||||
#define CONFIG_A1000 4
|
||||
#define CONFIG_ECS 8
|
||||
|
||||
#define CONFIG_FLOPPY1X 0
|
||||
#define CONFIG_FLOPPY2X 1
|
||||
|
||||
#define RESET_NORMAL 0
|
||||
#define RESET_BOOTLOADER 1
|
||||
|
||||
#define OSD_ARROW_LEFT 1
|
||||
#define OSD_ARROW_RIGHT 2
|
||||
|
||||
/*functions*/
|
||||
void OsdSetTitle(char *s,int arrow); // arrow > 0 = display right arrow in bottom right, < 0 = display left arrow
|
||||
void OsdWrite(unsigned char n, char *s, unsigned char inver, unsigned char stipple);
|
||||
void OsdWriteOffset(unsigned char n, char *s, unsigned char inver, unsigned char stipple, char offset); // Used for scrolling "Exit" text downwards...
|
||||
void OsdClear(void);
|
||||
void OsdEnable(unsigned char mode);
|
||||
void OsdDisable(void);
|
||||
void OsdWaitVBL(void);
|
||||
void OsdReset(unsigned char boot);
|
||||
void ConfigFilter(unsigned char lores, unsigned char hires);
|
||||
void ConfigMemory(unsigned char memory);
|
||||
void ConfigCPU(unsigned char cpu);
|
||||
void ConfigChipset(unsigned char chipset);
|
||||
void ConfigFloppy(unsigned char drives, unsigned char speed);
|
||||
void ConfigScanlines(unsigned char scanlines);
|
||||
void ConfigIDE(unsigned char gayle, unsigned char master, unsigned char slave);
|
||||
void ConfigAutofire(unsigned char autofire);
|
||||
unsigned char OsdGetCtrl(void);
|
||||
unsigned char GetASCIIKey(unsigned char c);
|
||||
void OSD_PrintText(unsigned char line, char *text, unsigned long start, unsigned long width, unsigned long offset, unsigned char invert);
|
||||
void OsdWriteDoubleSize(unsigned char n, char *s, unsigned char pass);
|
||||
//void OsdDrawLogo(unsigned char n, char row);
|
||||
void OsdDrawLogo(unsigned char n, char row,char superimpose);
|
||||
void ScrollText(char n,const char *str, int len, int max_len,unsigned char invert);
|
||||
void ScrollReset();
|
||||
void StarsInit();
|
||||
void StarsUpdate();
|
||||
|
||||
void OsdKeySet(unsigned char);
|
||||
unsigned char OsdKeyGet();
|
||||
|
||||
#endif
|
||||
|
||||
81
rafile.c
Normal file
81
rafile.c
Normal file
@@ -0,0 +1,81 @@
|
||||
#include "rafile.h"
|
||||
|
||||
int RARead(RAFile *file,unsigned char *pBuffer, unsigned long bytes)
|
||||
{
|
||||
int result=1;
|
||||
// Since we can only read from the SD card on 512-byte aligned boundaries,
|
||||
// we need to copy in multiple pieces.
|
||||
unsigned long blockoffset=file->ptr&511; // Offset within the current 512 block at which the previous read finished
|
||||
// Bytes blockoffset to 512 will be drained first, before reading new data.
|
||||
|
||||
if(blockoffset) // If blockoffset is zero we'll just use aligned reads and don't need to drain the buffer.
|
||||
{
|
||||
int i;
|
||||
int l=bytes;
|
||||
if(l>512)
|
||||
l=512;
|
||||
for(i=blockoffset;i<l;++i)
|
||||
{
|
||||
*pBuffer++=file->buffer[i];
|
||||
}
|
||||
file->ptr+=l-blockoffset;
|
||||
bytes-=l-blockoffset;
|
||||
}
|
||||
|
||||
// We've now read any bytes left over from a previous read. If any data remains to be read we can read it
|
||||
// in 512-byte aligned chunks, until the last block.
|
||||
while(bytes>511)
|
||||
{
|
||||
result&=FileRead(&file->file,pBuffer); // Read direct to pBuffer
|
||||
FileNextSector(&file->file);
|
||||
bytes-=512;
|
||||
file->ptr+=512;
|
||||
pBuffer+=512;
|
||||
}
|
||||
|
||||
if(bytes) // Do we have any bytes left to read?
|
||||
{
|
||||
int i;
|
||||
result&=FileRead(&file->file,file->buffer); // Read to temporary buffer, allowing us to preserve any leftover for the next read.
|
||||
FileNextSector(&file->file);
|
||||
for(i=0;i<bytes;++i)
|
||||
{
|
||||
*pBuffer++=file->buffer[i];
|
||||
}
|
||||
file->ptr+=bytes;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
int RASeek(RAFile *file,unsigned long offset,unsigned long origin)
|
||||
{
|
||||
int result=1;
|
||||
unsigned long blockoffset;
|
||||
unsigned long blockaddress;
|
||||
if(origin==SEEK_CUR)
|
||||
offset+=file->ptr;
|
||||
blockoffset=offset&511;
|
||||
blockaddress=offset-blockoffset; // 512-byte-aligned...
|
||||
result&=FileSeek(&file->file,blockaddress,SEEK_SET);
|
||||
if(result && blockoffset) // If we're seeking into the middle of a block, we need to buffer it...
|
||||
{
|
||||
result&=FileRead(&file->file,file->buffer);
|
||||
FileNextSector(&file->file);
|
||||
}
|
||||
file->ptr=offset;
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
int RAOpen(RAFile *file,const char *filename)
|
||||
{
|
||||
int result=1;
|
||||
if(!file)
|
||||
return(0);
|
||||
result=FileOpen(&file->file,filename);
|
||||
file->size=file->file.size;
|
||||
file->ptr=0;
|
||||
return(result);
|
||||
}
|
||||
|
||||
35
rafile.h
Normal file
35
rafile.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef RAFILE_H
|
||||
#define RAFILE_H
|
||||
|
||||
/* Utility functions to provide the Minimig OSD code with file access
|
||||
at single-byte rather than 512-byte-block granularity.
|
||||
Copyright (c) 2012 by Alastair M. Robinson
|
||||
|
||||
Contributed to the Minimig project, which is free software;
|
||||
you can redistribute it and/or modify it under the terms of
|
||||
the GNU General Public License as published by the Free Software Foundation;
|
||||
either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
Minimig is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "fat.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
fileTYPE file;
|
||||
unsigned long size;
|
||||
unsigned long ptr;
|
||||
unsigned char buffer[512]; // Each RandomAccessFile has its own sector_buffer
|
||||
} RAFile;
|
||||
|
||||
int RARead(RAFile *file,unsigned char *pBuffer, unsigned long bytes);
|
||||
int RASeek(RAFile *file,unsigned long offset,unsigned long origin);
|
||||
int RAOpen(RAFile *file,const char *filename);
|
||||
#endif
|
||||
56
swap.c
Normal file
56
swap.c
Normal file
@@ -0,0 +1,56 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// swap.c //
|
||||
// Endianness swap functions //
|
||||
// //
|
||||
// Copyright 2012- Christian Vogelgsang, A.M. Robinson, Rok Krajnc //
|
||||
// //
|
||||
// This file is part of Minimig //
|
||||
// //
|
||||
// Minimig is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// Minimig is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Changelog //
|
||||
// //
|
||||
// 2012-08-02 - rok.krajnc@gmail.com //
|
||||
// Functions are now generic - removed assembler code. Added function-like //
|
||||
// macros (gcc specific!). //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "swap.h"
|
||||
|
||||
|
||||
#ifndef SWAP_MACROS
|
||||
|
||||
uint32_t SwapBBBB(uint32_t i)
|
||||
{
|
||||
return ((i&0x00ff0000)>>8) | ((i&0xff000000)>>24) | ((i&0x000000ff)<<24) | ((i&0x0000ff00)<<8);
|
||||
}
|
||||
|
||||
|
||||
uint16_t SwapBB(uint16_t i)
|
||||
{
|
||||
return ((i&0x00ff)<<8) | ((i&0xff00)>>8);
|
||||
}
|
||||
|
||||
|
||||
uint32_t SwapWW(uint32_t i)
|
||||
{
|
||||
//return ((i&0x0000ffff)<<16) | ((i&0xffff0000)>>16);
|
||||
return ((i<<16) | (i>>16));
|
||||
}
|
||||
|
||||
#endif // SWAP_MACROS
|
||||
|
||||
67
swap.h
Normal file
67
swap.h
Normal file
@@ -0,0 +1,67 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// swap.h //
|
||||
// Endianness swap functions //
|
||||
// //
|
||||
// Copyright 2012- Christian Vogelgsang, A.M. Robinson, Rok Krajnc //
|
||||
// //
|
||||
// This file is part of Minimig //
|
||||
// //
|
||||
// Minimig is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// Minimig is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Changelog //
|
||||
// //
|
||||
// 2012-08-02 - rok.krajnc@gmail.com //
|
||||
// Functions are now generic - removed assembler code. Added function-like //
|
||||
// macros (gcc specific!). //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#ifndef __SWAP_H__
|
||||
#define __SWAP_H__
|
||||
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
|
||||
//// config defines ////
|
||||
|
||||
// use macros / functions
|
||||
#define SWAP_MACROS
|
||||
|
||||
|
||||
#ifdef SWAP_MACROS
|
||||
//// macros ////
|
||||
#ifdef SWAP
|
||||
#define SwapBBBB(x) ({ typeof(x) _x = (x); ((_x&0x00ff0000)>>8) | ((_x&0xff000000)>>24) | ((_x&0x000000ff)<<24) | ((_x&0x0000ff00)<<8); })
|
||||
#define SwapBB(x) ({ typeof(x) _x = (x); ((_x&0x00ff)<<8) | ((_x&0xff00)>>8); })
|
||||
#define SwapWW(x) ({ typeof(x) _x = (x); ((_x&0x0000ffff)<<16) | ((_x&0xffff0000)>>16); })
|
||||
#else
|
||||
#define SwapBBBB(x) (x)
|
||||
#define SwapBB(x) (x)
|
||||
#define SwapWW(x) (x)
|
||||
#endif // SWAP
|
||||
|
||||
#else
|
||||
|
||||
//// function declarations ////
|
||||
uint32_t SwapBBBB (uint32_t i);
|
||||
uint16_t SwapBB (uint16_t i);
|
||||
uint32_t SwapWW (uint32_t i);
|
||||
|
||||
#endif // SWAP_MACROS
|
||||
|
||||
#endif // __SWAP_H__
|
||||
|
||||
60
swi.h
Normal file
60
swi.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/* SWI numbers for RDP (Demon) monitor. */
|
||||
#define SWI_WriteC 0x0
|
||||
#define SWI_Write0 0x2
|
||||
#define SWI_ReadC 0x4
|
||||
#define SWI_CLI 0x5
|
||||
#define SWI_GetEnv 0x10
|
||||
#define SWI_Exit 0x11
|
||||
#define SWI_EnterOS 0x16
|
||||
|
||||
#define SWI_GetErrno 0x60
|
||||
#define SWI_Clock 0x61
|
||||
#define SWI_Time 0x63
|
||||
#define SWI_Remove 0x64
|
||||
#define SWI_Rename 0x65
|
||||
#define SWI_Open 0x66
|
||||
|
||||
#define SWI_Close 0x68
|
||||
#define SWI_Write 0x69
|
||||
#define SWI_Read 0x6a
|
||||
#define SWI_Seek 0x6b
|
||||
#define SWI_Flen 0x6c
|
||||
|
||||
#define SWI_IsTTY 0x6e
|
||||
#define SWI_TmpNam 0x6f
|
||||
#define SWI_InstallHandler 0x70
|
||||
#define SWI_GenerateError 0x71
|
||||
|
||||
|
||||
/* Now the SWI numbers and reason codes for RDI (Angel) monitors. */
|
||||
#define AngelSWI_ARM 0x123456
|
||||
#ifdef __thumb__
|
||||
#define AngelSWI 0xAB
|
||||
#else
|
||||
#define AngelSWI AngelSWI_ARM
|
||||
#endif
|
||||
|
||||
/* The reason codes: */
|
||||
#define AngelSWI_Reason_Open 0x01
|
||||
#define AngelSWI_Reason_Close 0x02
|
||||
#define AngelSWI_Reason_WriteC 0x03
|
||||
#define AngelSWI_Reason_Write0 0x04
|
||||
#define AngelSWI_Reason_Write 0x05
|
||||
#define AngelSWI_Reason_Read 0x06
|
||||
#define AngelSWI_Reason_ReadC 0x07
|
||||
#define AngelSWI_Reason_IsTTY 0x09
|
||||
#define AngelSWI_Reason_Seek 0x0A
|
||||
#define AngelSWI_Reason_FLen 0x0C
|
||||
#define AngelSWI_Reason_TmpNam 0x0D
|
||||
#define AngelSWI_Reason_Remove 0x0E
|
||||
#define AngelSWI_Reason_Rename 0x0F
|
||||
#define AngelSWI_Reason_Clock 0x10
|
||||
#define AngelSWI_Reason_Time 0x11
|
||||
#define AngelSWI_Reason_System 0x12
|
||||
#define AngelSWI_Reason_Errno 0x13
|
||||
#define AngelSWI_Reason_GetCmdLine 0x15
|
||||
#define AngelSWI_Reason_HeapInfo 0x16
|
||||
#define AngelSWI_Reason_EnterSVC 0x17
|
||||
#define AngelSWI_Reason_ReportException 0x18
|
||||
#define ADP_Stopped_ApplicationExit ((2 << 16) + 38)
|
||||
#define ADP_Stopped_RunTimeError ((2 << 16) + 35)
|
||||
646
syscalls.c
Normal file
646
syscalls.c
Normal file
@@ -0,0 +1,646 @@
|
||||
/* Support files for GNU libc. Files in the system namespace go here.
|
||||
Files in the C namespace (ie those that do not start with an
|
||||
underscore) go in .c. */
|
||||
|
||||
// http://balau82.wordpress.com/2011/09/03/using-codesourcery-bare-metal-toolchain-for-cortex-m3/
|
||||
|
||||
#include <_ansi.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/times.h>
|
||||
#include <errno.h>
|
||||
#include <reent.h>
|
||||
#include <unistd.h>
|
||||
#include "swi.h"
|
||||
#include "AT91SAM7S256.h"
|
||||
|
||||
/* Forward prototypes. */
|
||||
int _system _PARAMS ((const char *));
|
||||
int _rename _PARAMS ((const char *, const char *));
|
||||
/* Different versions of newlib name this differentely. */
|
||||
int isatty _PARAMS ((int));
|
||||
int _isatty _PARAMS ((int));
|
||||
clock_t _times _PARAMS ((struct tms *));
|
||||
int _gettimeofday _PARAMS ((struct timeval *, struct timezone *));
|
||||
void _raise _PARAMS ((void));
|
||||
int _unlink _PARAMS ((void));
|
||||
int _link _PARAMS ((void));
|
||||
int _stat _PARAMS ((const char *, struct stat *));
|
||||
int _fstat _PARAMS ((int, struct stat *));
|
||||
caddr_t _sbrk _PARAMS ((int));
|
||||
int _getpid _PARAMS ((int));
|
||||
int _kill _PARAMS ((int, int));
|
||||
void _exit _PARAMS ((int));
|
||||
int _close _PARAMS ((int));
|
||||
int _swiclose _PARAMS ((int));
|
||||
int _open _PARAMS ((const char *, int, ...));
|
||||
int _swiopen _PARAMS ((const char *, int));
|
||||
int _write _PARAMS ((int, char *, int));
|
||||
int _swiwrite _PARAMS ((int, char *, int));
|
||||
int _lseek _PARAMS ((int, int, int));
|
||||
int _swilseek _PARAMS ((int, int, int));
|
||||
int _read _PARAMS ((int, char *, int));
|
||||
int _swiread _PARAMS ((int, char *, int));
|
||||
void initialise_monitor_handles _PARAMS ((void));
|
||||
|
||||
static int wrap _PARAMS ((int));
|
||||
static int error _PARAMS ((int));
|
||||
static int get_errno _PARAMS ((void));
|
||||
static int remap_handle _PARAMS ((int));
|
||||
static int do_AngelSWI _PARAMS ((int, void *));
|
||||
static int findslot _PARAMS ((int));
|
||||
|
||||
/* Register name faking - works in collusion with the linker. */
|
||||
register char * stack_ptr asm ("sp");
|
||||
|
||||
|
||||
/* following is copied from libc/stdio/local.h to check std streams */
|
||||
extern void _EXFUN(__sinit,(struct _reent *));
|
||||
#define CHECK_INIT(ptr) \
|
||||
do \
|
||||
{ \
|
||||
if ((ptr) && !(ptr)->__sdidinit) \
|
||||
__sinit (ptr); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* Adjust our internal handles to stay away from std* handles. */
|
||||
#define FILE_HANDLE_OFFSET (0x20)
|
||||
|
||||
static int monitor_stdin;
|
||||
static int monitor_stdout;
|
||||
static int monitor_stderr;
|
||||
|
||||
/* Struct used to keep track of the file position, just so we
|
||||
can implement fseek(fh,x,SEEK_CUR). */
|
||||
typedef struct
|
||||
{
|
||||
int handle;
|
||||
int pos;
|
||||
}
|
||||
poslog;
|
||||
|
||||
#define MAX_OPEN_FILES 20
|
||||
static poslog openfiles [MAX_OPEN_FILES];
|
||||
|
||||
static int
|
||||
findslot (int fh)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MAX_OPEN_FILES; i ++)
|
||||
if (openfiles[i].handle == fh)
|
||||
break;
|
||||
return i;
|
||||
}
|
||||
|
||||
#ifdef ARM_RDI_MONITOR
|
||||
|
||||
static inline int
|
||||
do_AngelSWI (int reason, void * arg)
|
||||
{
|
||||
int value;
|
||||
asm volatile ("mov r0, %1; mov r1, %2; swi %a3; mov %0, r0"
|
||||
: "=r" (value) /* Outputs */
|
||||
: "r" (reason), "r" (arg), "i" (AngelSWI) /* Inputs */
|
||||
: "r0", "r1", "r2", "r3", "ip", "lr", "memory", "cc"
|
||||
/* Clobbers r0 and r1, and lr if in supervisor mode */);
|
||||
/* Accordingly to page 13-77 of ARM DUI 0040D other registers
|
||||
can also be clobbered. Some memory positions may also be
|
||||
changed by a system call, so they should not be kept in
|
||||
registers. Note: we are assuming the manual is right and
|
||||
Angel is respecting the APCS. */
|
||||
return value;
|
||||
}
|
||||
#endif /* ARM_RDI_MONITOR */
|
||||
|
||||
/* Function to convert std(in|out|err) handles to internal versions. */
|
||||
static int
|
||||
remap_handle (int fh)
|
||||
{
|
||||
CHECK_INIT(_REENT);
|
||||
|
||||
if (fh == STDIN_FILENO)
|
||||
return monitor_stdin;
|
||||
if (fh == STDOUT_FILENO)
|
||||
return monitor_stdout;
|
||||
if (fh == STDERR_FILENO)
|
||||
return monitor_stderr;
|
||||
|
||||
return fh - FILE_HANDLE_OFFSET;
|
||||
}
|
||||
|
||||
void
|
||||
initialise_monitor_handles (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifdef ARM_RDI_MONITOR
|
||||
int volatile block[3];
|
||||
|
||||
block[0] = (int) ":tt";
|
||||
block[2] = 3; /* length of filename */
|
||||
block[1] = 0; /* mode "r" */
|
||||
monitor_stdin = do_AngelSWI (AngelSWI_Reason_Open, (void *) block);
|
||||
|
||||
block[0] = (int) ":tt";
|
||||
block[2] = 3; /* length of filename */
|
||||
block[1] = 4; /* mode "w" */
|
||||
monitor_stdout = monitor_stderr = do_AngelSWI (AngelSWI_Reason_Open, (void *) block);
|
||||
#else
|
||||
int fh;
|
||||
const char * name;
|
||||
|
||||
name = ":tt";
|
||||
asm ("mov r0,%2; mov r1, #0; swi %a1; mov %0, r0"
|
||||
: "=r"(fh)
|
||||
: "i" (SWI_Open),"r"(name)
|
||||
: "r0","r1");
|
||||
monitor_stdin = fh;
|
||||
|
||||
name = ":tt";
|
||||
asm ("mov r0,%2; mov r1, #4; swi %a1; mov %0, r0"
|
||||
: "=r"(fh)
|
||||
: "i" (SWI_Open),"r"(name)
|
||||
: "r0","r1");
|
||||
monitor_stdout = monitor_stderr = fh;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < MAX_OPEN_FILES; i ++)
|
||||
openfiles[i].handle = -1;
|
||||
|
||||
openfiles[0].handle = monitor_stdin;
|
||||
openfiles[0].pos = 0;
|
||||
openfiles[1].handle = monitor_stdout;
|
||||
openfiles[1].pos = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
get_errno (void)
|
||||
{
|
||||
#ifdef ARM_RDI_MONITOR
|
||||
return do_AngelSWI (AngelSWI_Reason_Errno, NULL);
|
||||
#else
|
||||
asm ("swi %a0" :: "i" (SWI_GetErrno));
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
error (int result)
|
||||
{
|
||||
errno = get_errno ();
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
wrap (int result)
|
||||
{
|
||||
if (result == -1)
|
||||
return error (-1);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Returns # chars not! written. */
|
||||
int
|
||||
_swiread (int file,
|
||||
char * ptr,
|
||||
int len)
|
||||
{
|
||||
int fh = remap_handle (file);
|
||||
#ifdef ARM_RDI_MONITOR
|
||||
int block[3];
|
||||
|
||||
block[0] = fh;
|
||||
block[1] = (int) ptr;
|
||||
block[2] = len;
|
||||
|
||||
return do_AngelSWI (AngelSWI_Reason_Read, block);
|
||||
#else
|
||||
asm ("mov r0, %1; mov r1, %2;mov r2, %3; swi %a0"
|
||||
: /* No outputs */
|
||||
: "i"(SWI_Read), "r"(fh), "r"(ptr), "r"(len)
|
||||
: "r0","r1","r2");
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
_read (int file,
|
||||
char * ptr,
|
||||
int len)
|
||||
{
|
||||
int slot = findslot (remap_handle (file));
|
||||
int x = _swiread (file, ptr, len);
|
||||
|
||||
if (x < 0)
|
||||
return error (-1);
|
||||
|
||||
if (slot != MAX_OPEN_FILES)
|
||||
openfiles [slot].pos += len - x;
|
||||
|
||||
/* x == len is not an error, at least if we want feof() to work. */
|
||||
return len - x;
|
||||
}
|
||||
|
||||
int
|
||||
_swilseek (int file,
|
||||
int ptr,
|
||||
int dir)
|
||||
{
|
||||
int res;
|
||||
int fh = remap_handle (file);
|
||||
int slot = findslot (fh);
|
||||
#ifdef ARM_RDI_MONITOR
|
||||
int block[2];
|
||||
#endif
|
||||
|
||||
if (dir == SEEK_CUR)
|
||||
{
|
||||
if (slot == MAX_OPEN_FILES)
|
||||
return -1;
|
||||
ptr = openfiles[slot].pos + ptr;
|
||||
dir = SEEK_SET;
|
||||
}
|
||||
|
||||
#ifdef ARM_RDI_MONITOR
|
||||
if (dir == SEEK_END)
|
||||
{
|
||||
block[0] = fh;
|
||||
ptr += do_AngelSWI (AngelSWI_Reason_FLen, block);
|
||||
}
|
||||
|
||||
/* This code only does absolute seeks. */
|
||||
block[0] = remap_handle (file);
|
||||
block[1] = ptr;
|
||||
res = do_AngelSWI (AngelSWI_Reason_Seek, block);
|
||||
#else
|
||||
if (dir == SEEK_END)
|
||||
{
|
||||
asm ("mov r0, %2; swi %a1; mov %0, r0"
|
||||
: "=r" (res)
|
||||
: "i" (SWI_Flen), "r" (fh)
|
||||
: "r0");
|
||||
ptr += res;
|
||||
}
|
||||
|
||||
/* This code only does absolute seeks. */
|
||||
asm ("mov r0, %2; mov r1, %3; swi %a1; mov %0, r0"
|
||||
: "=r" (res)
|
||||
: "i" (SWI_Seek), "r" (fh), "r" (ptr)
|
||||
: "r0", "r1");
|
||||
#endif
|
||||
|
||||
if (slot != MAX_OPEN_FILES && res == 0)
|
||||
openfiles[slot].pos = ptr;
|
||||
|
||||
/* This is expected to return the position in the file. */
|
||||
return res == 0 ? ptr : -1;
|
||||
}
|
||||
|
||||
int
|
||||
_lseek (int file,
|
||||
int ptr,
|
||||
int dir)
|
||||
{
|
||||
return wrap (_swilseek (file, ptr, dir));
|
||||
}
|
||||
|
||||
/* Returns #chars not! written. */
|
||||
int
|
||||
_swiwrite (
|
||||
int file,
|
||||
char * ptr,
|
||||
int len)
|
||||
{
|
||||
int fh = remap_handle (file);
|
||||
#ifdef ARM_RDI_MONITOR
|
||||
int block[3];
|
||||
|
||||
block[0] = fh;
|
||||
block[1] = (int) ptr;
|
||||
block[2] = len;
|
||||
|
||||
return do_AngelSWI (AngelSWI_Reason_Write, block);
|
||||
#else
|
||||
asm ("mov r0, %1; mov r1, %2;mov r2, %3; swi %a0"
|
||||
: /* No outputs */
|
||||
: "i"(SWI_Write), "r"(fh), "r"(ptr), "r"(len)
|
||||
: "r0","r1","r2");
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
_write (int file,
|
||||
char * ptr,
|
||||
int len) {
|
||||
volatile AT91PS_USART pUart = AT91C_BASE_US0;
|
||||
|
||||
int l = len;
|
||||
while(l--) {
|
||||
if(*ptr == '\n') {
|
||||
while(!(pUart->US_CSR & AT91C_US_TXRDY));
|
||||
pUart->US_THR = '\r';
|
||||
}
|
||||
|
||||
while(!(pUart->US_CSR & AT91C_US_TXRDY));
|
||||
pUart->US_THR = *ptr;
|
||||
|
||||
if(*ptr == '\r') {
|
||||
while(!(pUart->US_CSR & AT91C_US_TXRDY));
|
||||
pUart->US_THR = '\n';
|
||||
}
|
||||
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
extern int strlen (const char *);
|
||||
|
||||
int
|
||||
_swiopen (const char * path,
|
||||
int flags)
|
||||
{
|
||||
int aflags = 0, fh;
|
||||
#ifdef ARM_RDI_MONITOR
|
||||
int block[3];
|
||||
#endif
|
||||
|
||||
int i = findslot (-1);
|
||||
|
||||
if (i == MAX_OPEN_FILES)
|
||||
return -1;
|
||||
|
||||
/* The flags are Unix-style, so we need to convert them. */
|
||||
#ifdef O_BINARY
|
||||
if (flags & O_BINARY)
|
||||
aflags |= 1;
|
||||
#endif
|
||||
|
||||
if (flags & O_RDWR)
|
||||
aflags |= 2;
|
||||
|
||||
if (flags & O_CREAT)
|
||||
aflags |= 4;
|
||||
|
||||
if (flags & O_TRUNC)
|
||||
aflags |= 4;
|
||||
|
||||
if (flags & O_APPEND)
|
||||
{
|
||||
aflags &= ~4; /* Can't ask for w AND a; means just 'a'. */
|
||||
aflags |= 8;
|
||||
}
|
||||
|
||||
#ifdef ARM_RDI_MONITOR
|
||||
block[0] = (int) path;
|
||||
block[2] = strlen (path);
|
||||
block[1] = aflags;
|
||||
|
||||
fh = do_AngelSWI (AngelSWI_Reason_Open, block);
|
||||
|
||||
#else
|
||||
asm ("mov r0,%2; mov r1, %3; swi %a1; mov %0, r0"
|
||||
: "=r"(fh)
|
||||
: "i" (SWI_Open),"r"(path),"r"(aflags)
|
||||
: "r0","r1");
|
||||
#endif
|
||||
|
||||
if (fh >= 0)
|
||||
{
|
||||
openfiles[i].handle = fh;
|
||||
openfiles[i].pos = 0;
|
||||
}
|
||||
|
||||
return fh >= 0 ? fh + FILE_HANDLE_OFFSET : error (fh);
|
||||
}
|
||||
|
||||
int
|
||||
_open (const char * path,
|
||||
int flags,
|
||||
...)
|
||||
{
|
||||
return wrap (_swiopen (path, flags));
|
||||
}
|
||||
|
||||
int
|
||||
_swiclose (int file)
|
||||
{
|
||||
int myhan = remap_handle (file);
|
||||
int slot = findslot (myhan);
|
||||
|
||||
if (slot != MAX_OPEN_FILES)
|
||||
openfiles[slot].handle = -1;
|
||||
|
||||
#ifdef ARM_RDI_MONITOR
|
||||
return do_AngelSWI (AngelSWI_Reason_Close, & myhan);
|
||||
#else
|
||||
asm ("mov r0, %1; swi %a0" :: "i" (SWI_Close),"r"(myhan):"r0");
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
_close (int file)
|
||||
{
|
||||
return wrap (_swiclose (file));
|
||||
}
|
||||
|
||||
void
|
||||
_exit (int n)
|
||||
{
|
||||
/* FIXME: return code is thrown away. */
|
||||
|
||||
#ifdef ARM_RDI_MONITOR
|
||||
do_AngelSWI (AngelSWI_Reason_ReportException,
|
||||
(void *) ADP_Stopped_ApplicationExit);
|
||||
#else
|
||||
asm ("swi %a0" :: "i" (SWI_Exit));
|
||||
#endif
|
||||
n = n;
|
||||
|
||||
while(1);
|
||||
}
|
||||
|
||||
int
|
||||
_kill (int n, int m)
|
||||
{
|
||||
#ifdef ARM_RDI_MONITOR
|
||||
return do_AngelSWI (AngelSWI_Reason_ReportException,
|
||||
(void *) ADP_Stopped_ApplicationExit);
|
||||
#else
|
||||
asm ("swi %a0" :: "i" (SWI_Exit));
|
||||
#endif
|
||||
n = n; m = m;
|
||||
}
|
||||
|
||||
int
|
||||
_getpid (int n)
|
||||
{
|
||||
return 1;
|
||||
n = n;
|
||||
}
|
||||
|
||||
caddr_t
|
||||
_sbrk (int incr)
|
||||
{
|
||||
extern char end asm ("end"); /* Defined by the linker. */
|
||||
static char * heap_end = NULL;
|
||||
char * prev_heap_end;
|
||||
|
||||
if (heap_end == NULL)
|
||||
heap_end = & end;
|
||||
|
||||
prev_heap_end = heap_end;
|
||||
|
||||
if (heap_end + incr > stack_ptr)
|
||||
{
|
||||
/* Some of the libstdc++-v3 tests rely upon detecting
|
||||
out of memory errors, so do not abort here. */
|
||||
#if 0
|
||||
extern void abort (void);
|
||||
|
||||
_write (1, "_sbrk: Heap and stack collision\n", 32);
|
||||
|
||||
abort ();
|
||||
#else
|
||||
errno = ENOMEM;
|
||||
return (caddr_t) -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
heap_end += incr;
|
||||
|
||||
return (caddr_t) prev_heap_end;
|
||||
}
|
||||
|
||||
extern void *memset (void *, int, size_t);
|
||||
|
||||
int
|
||||
_fstat (int file, struct stat * st)
|
||||
{
|
||||
memset (st, 0, sizeof (* st));
|
||||
st->st_mode = S_IFCHR;
|
||||
st->st_blksize = 1024;
|
||||
return 0;
|
||||
file = file;
|
||||
}
|
||||
|
||||
int _stat (const char *fname, struct stat *st)
|
||||
{
|
||||
int file;
|
||||
|
||||
/* The best we can do is try to open the file readonly. If it exists,
|
||||
then we can guess a few things about it. */
|
||||
if ((file = _open (fname, O_RDONLY)) < 0)
|
||||
return -1;
|
||||
|
||||
memset (st, 0, sizeof (* st));
|
||||
st->st_mode = S_IFREG | S_IREAD;
|
||||
st->st_blksize = 1024;
|
||||
_swiclose (file); /* Not interested in the error. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_link (void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
_unlink (void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
_raise (void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
_gettimeofday (struct timeval * tp, struct timezone * tzp)
|
||||
{
|
||||
|
||||
if (tp)
|
||||
{
|
||||
/* Ask the host for the seconds since the Unix epoch. */
|
||||
#ifdef ARM_RDI_MONITOR
|
||||
tp->tv_sec = do_AngelSWI (AngelSWI_Reason_Time,NULL);
|
||||
#else
|
||||
{
|
||||
int value;
|
||||
asm ("swi %a1; mov %0, r0" : "=r" (value): "i" (SWI_Time) : "r0");
|
||||
tp->tv_sec = value;
|
||||
}
|
||||
#endif
|
||||
tp->tv_usec = 0;
|
||||
}
|
||||
|
||||
/* Return fixed data for the timezone. */
|
||||
if (tzp)
|
||||
{
|
||||
tzp->tz_minuteswest = 0;
|
||||
tzp->tz_dsttime = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return a clock that ticks at 100Hz. */
|
||||
clock_t
|
||||
_times (struct tms * tp)
|
||||
{
|
||||
clock_t timeval;
|
||||
|
||||
#ifdef ARM_RDI_MONITOR
|
||||
timeval = do_AngelSWI (AngelSWI_Reason_Clock,NULL);
|
||||
#else
|
||||
asm ("swi %a1; mov %0, r0" : "=r" (timeval): "i" (SWI_Clock) : "r0");
|
||||
#endif
|
||||
|
||||
if (tp)
|
||||
{
|
||||
tp->tms_utime = timeval; /* user time */
|
||||
tp->tms_stime = 0; /* system time */
|
||||
tp->tms_cutime = 0; /* user time, children */
|
||||
tp->tms_cstime = 0; /* system time, children */
|
||||
}
|
||||
|
||||
return timeval;
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
isatty (int fd)
|
||||
{
|
||||
return 1;
|
||||
fd = fd;
|
||||
}
|
||||
|
||||
int
|
||||
_isatty (int fd)
|
||||
{
|
||||
return 1;
|
||||
fd = fd;
|
||||
}
|
||||
|
||||
int
|
||||
_system (const char *s)
|
||||
{
|
||||
if (s == NULL)
|
||||
return 0;
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
_rename (const char * oldpath, const char * newpath)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
547
tos.c
Normal file
547
tos.c
Normal file
@@ -0,0 +1,547 @@
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
#include "hardware.h"
|
||||
|
||||
#include "tos.h"
|
||||
#include "fat.h"
|
||||
#include "fpga.h"
|
||||
|
||||
#define TOS_BASE_ADDRESS_192k 0xfc0000
|
||||
#define TOS_BASE_ADDRESS_256k 0xe00000
|
||||
#define CART_BASE_ADDRESS 0xfa0000
|
||||
#define VIDEO_BASE_ADDRESS 0x010000
|
||||
|
||||
unsigned long tos_system_ctrl = TOS_MEMCONFIG_4M;
|
||||
|
||||
static unsigned char font[2048]; // buffer for 8x16 atari font
|
||||
|
||||
static struct {
|
||||
fileTYPE file;
|
||||
unsigned char sides;
|
||||
unsigned char spt;
|
||||
} disk[2];
|
||||
|
||||
static unsigned char floppy_buffer[512];
|
||||
|
||||
static void mist_memory_set_address(unsigned long a) {
|
||||
a >>= 1; // make word address
|
||||
|
||||
EnableFpga();
|
||||
SPI(MIST_SET_ADDRESS);
|
||||
SPI((a >> 24) & 0xff);
|
||||
SPI((a >> 16) & 0xff);
|
||||
SPI((a >> 8) & 0xff);
|
||||
SPI((a >> 0) & 0xff);
|
||||
DisableFpga();
|
||||
}
|
||||
|
||||
static void mist_set_control(unsigned short ctrl) {
|
||||
EnableFpga();
|
||||
SPI(MIST_SET_CONTROL);
|
||||
SPI((ctrl >> 8) & 0xff);
|
||||
SPI((ctrl >> 0) & 0xff);
|
||||
DisableFpga();
|
||||
}
|
||||
|
||||
static void hexdump(void *data, unsigned long size, unsigned long offset) {
|
||||
int i, b2c;
|
||||
unsigned long n=0;
|
||||
char *ptr = data;
|
||||
|
||||
if(!size) return;
|
||||
|
||||
while(size>0) {
|
||||
iprintf("%08x: ", n + offset);
|
||||
|
||||
b2c = (size>16)?16:size;
|
||||
for(i=0;i<b2c;i++) iprintf("%02x ", 0xff&ptr[i]);
|
||||
iprintf(" ");
|
||||
for(i=0;i<(16-b2c);i++) iprintf(" ");
|
||||
for(i=0;i<b2c;i++) iprintf("%c", isprint(ptr[i])?ptr[i]:'.');
|
||||
iprintf("\n");
|
||||
ptr += b2c;
|
||||
size -= b2c;
|
||||
n += b2c;
|
||||
}
|
||||
}
|
||||
|
||||
static void mist_memory_read(char *data, unsigned long words) {
|
||||
EnableFpga();
|
||||
SPI(MIST_READ_MEMORY);
|
||||
|
||||
// transmitted bytes must be multiple of 2 (-> words)
|
||||
while(words--) {
|
||||
*data++ = SPI(0);
|
||||
*data++ = SPI(0);
|
||||
}
|
||||
|
||||
DisableFpga();
|
||||
}
|
||||
|
||||
static void mist_memory_write(char *data, unsigned long words) {
|
||||
EnableFpga();
|
||||
SPI(MIST_WRITE_MEMORY);
|
||||
|
||||
while(words--) {
|
||||
SPI(*data++);
|
||||
SPI(*data++);
|
||||
}
|
||||
|
||||
DisableFpga();
|
||||
}
|
||||
|
||||
void mist_memory_set(char data, unsigned long words) {
|
||||
EnableFpga();
|
||||
SPI(MIST_WRITE_MEMORY);
|
||||
|
||||
while(words--) {
|
||||
SPI(data);
|
||||
SPI(data);
|
||||
}
|
||||
|
||||
DisableFpga();
|
||||
}
|
||||
|
||||
static void mist_get_dmastate() {
|
||||
static unsigned char buffer[10];
|
||||
int i;
|
||||
|
||||
EnableFpga();
|
||||
SPI(MIST_GET_DMASTATE);
|
||||
for(i=0;i<10;i++)
|
||||
buffer[i] = SPI(0);
|
||||
DisableFpga();
|
||||
|
||||
// check if fdc is busy
|
||||
if(buffer[8] & 1) {
|
||||
// extract contents
|
||||
unsigned int dma_address = 256 * 256 * buffer[0] + 256 * buffer[1] + buffer[2];
|
||||
unsigned char scnt = buffer[3];
|
||||
unsigned char fdc_cmd = buffer[4];
|
||||
unsigned char fdc_track = buffer[5];
|
||||
unsigned char fdc_sector = buffer[6];
|
||||
unsigned char fdc_data = buffer[7];
|
||||
unsigned char drv_sel = 3-((buffer[8]>>2)&3);
|
||||
unsigned char drv_side = 1-((buffer[8]>>1)&1);
|
||||
|
||||
// check if a matching disk image has been inserted
|
||||
if(drv_sel && disk[drv_sel-1].file.size) {
|
||||
|
||||
// if the fdc has been asked to write protect the disks, then
|
||||
// write sector commands should never reach the oi controller
|
||||
|
||||
// read/write sector command
|
||||
if((fdc_cmd & 0xc0) == 0x80) {
|
||||
|
||||
// convert track/sector/side into disk offset
|
||||
unsigned int offset = drv_side;
|
||||
offset += fdc_track * disk[drv_sel-1].sides;
|
||||
offset *= disk[drv_sel-1].spt;
|
||||
offset += fdc_sector-1;
|
||||
|
||||
while(scnt) {
|
||||
DISKLED_ON;
|
||||
|
||||
FileSeek(&disk[drv_sel-1].file, offset, SEEK_SET);
|
||||
mist_memory_set_address(dma_address);
|
||||
|
||||
if((fdc_cmd & 0xe0) == 0x80) {
|
||||
// read from disk ...
|
||||
FileRead(&disk[drv_sel-1].file, floppy_buffer);
|
||||
// ... and copy to ram
|
||||
mist_memory_write(floppy_buffer, 256);
|
||||
} else {
|
||||
// read from ram ...
|
||||
mist_memory_read(floppy_buffer, 256);
|
||||
// ... and write to disk
|
||||
FileWrite(&(disk[drv_sel-1].file), floppy_buffer);
|
||||
}
|
||||
|
||||
DISKLED_OFF;
|
||||
|
||||
scnt--;
|
||||
dma_address += 512;
|
||||
offset += 1;
|
||||
}
|
||||
|
||||
EnableFpga();
|
||||
SPI(MIST_ACK_DMA);
|
||||
DisableFpga();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void tos_clr() {
|
||||
mist_memory_set_address(VIDEO_BASE_ADDRESS);
|
||||
mist_memory_set(0, 16000);
|
||||
}
|
||||
|
||||
// color test, used to test the shifter without CPU/TOS
|
||||
#define COLORS 20
|
||||
#define PLANES 4
|
||||
|
||||
static void tos_color_test() {
|
||||
unsigned short buffer[COLORS][PLANES];
|
||||
|
||||
int y;
|
||||
for(y=0;y<13;y++) {
|
||||
int i, j;
|
||||
for(i=0;i<COLORS;i++)
|
||||
for(j=0;j<PLANES;j++)
|
||||
buffer[i][j] = ((y+i) & (1<<j))?0xffff:0x0000;
|
||||
|
||||
for(i=0;i<16;i++) {
|
||||
mist_memory_set_address(VIDEO_BASE_ADDRESS + (16*y+i)*160);
|
||||
mist_memory_write((char*)buffer, COLORS*PLANES);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void tos_write(char *str) {
|
||||
static int y = 0;
|
||||
int l;
|
||||
int c = strlen(str);
|
||||
|
||||
{
|
||||
char buffer[c];
|
||||
|
||||
// 16 pixel lines
|
||||
for(l=0;l<16;l++) {
|
||||
char *p = str, *f=buffer;
|
||||
while(*p)
|
||||
*f++ = font[16 * *p++ + l];
|
||||
|
||||
mist_memory_set_address(VIDEO_BASE_ADDRESS + 80*(y+l));
|
||||
mist_memory_write(buffer, c/2);
|
||||
}
|
||||
}
|
||||
y+=16;
|
||||
}
|
||||
|
||||
static void tos_font_load() {
|
||||
fileTYPE file;
|
||||
if(FileOpen(&file,"SYSTEM FNT")) {
|
||||
if(file.size == 4096) {
|
||||
int i;
|
||||
for(i=0;i<4;i++) {
|
||||
FileRead(&file, font+i*512);
|
||||
FileNextSector(&file);
|
||||
}
|
||||
|
||||
tos_clr();
|
||||
|
||||
// tos_color_test();
|
||||
|
||||
tos_write("\016\017 MIST core \016\017 ");
|
||||
|
||||
} else
|
||||
iprintf("SYSTEM.FNT has wrong size\n");
|
||||
} else
|
||||
iprintf("SYSTEM.FNT not found\n");
|
||||
}
|
||||
|
||||
void tos_upload() {
|
||||
|
||||
// put cpu into reset
|
||||
mist_set_control(tos_system_ctrl | TOS_CONTROL_CPU_RESET);
|
||||
|
||||
tos_font_load();
|
||||
|
||||
// do the MiST core handling
|
||||
tos_write("Uploading TOS ... ");
|
||||
iprintf("Uploading TOS ...\n");
|
||||
|
||||
DISKLED_ON;
|
||||
|
||||
// upload and verify tos image
|
||||
fileTYPE file;
|
||||
if(FileOpen(&file,"TOS IMG")) {
|
||||
int i;
|
||||
char buffer[512];
|
||||
unsigned long time;
|
||||
unsigned long tos_base = TOS_BASE_ADDRESS_192k;
|
||||
|
||||
iprintf("TOS.IMG:\n size = %d\n", file.size);
|
||||
|
||||
if(file.size == 256*1024)
|
||||
tos_base = TOS_BASE_ADDRESS_256k;
|
||||
else if(file.size != 192*1024)
|
||||
iprintf("WARNING: Unexpected TOS size!\n");
|
||||
|
||||
int blocks = file.size / 512;
|
||||
iprintf(" blocks = %d\n", blocks);
|
||||
|
||||
iprintf(" address = $%08x\n", tos_base);
|
||||
|
||||
// extract base address
|
||||
FileRead(&file, buffer);
|
||||
|
||||
// clear first 16k
|
||||
mist_memory_set_address(0);
|
||||
mist_memory_set(0x00, 8192);
|
||||
|
||||
#if 0
|
||||
iprintf("Erasing: ");
|
||||
|
||||
// clear memory to increase chances of catching write problems
|
||||
mist_memory_set_address(tos_base);
|
||||
mist_memory_set(0x00, file.size/2);
|
||||
iprintf("done\n");
|
||||
#endif
|
||||
|
||||
time = GetTimer(0);
|
||||
iprintf("Uploading: [");
|
||||
|
||||
for(i=0;i<blocks;i++) {
|
||||
FileRead(&file, buffer);
|
||||
|
||||
// copy first 8 bytes to address 0 as well
|
||||
if(i == 0) {
|
||||
mist_memory_set_address(0);
|
||||
|
||||
// write first 4 words
|
||||
mist_memory_write(buffer, 4);
|
||||
|
||||
// set real tos base address
|
||||
mist_memory_set_address(tos_base);
|
||||
}
|
||||
|
||||
mist_memory_write(buffer, 256);
|
||||
|
||||
if(!(i & 7)) iprintf(".");
|
||||
|
||||
if(i != blocks-1)
|
||||
FileNextSector(&file);
|
||||
}
|
||||
iprintf("]\n");
|
||||
|
||||
time = GetTimer(0) - time;
|
||||
iprintf("TOS.IMG uploaded in %lu ms\r", time >> 20);
|
||||
|
||||
} else
|
||||
iprintf("Unable to find tos.img\n");
|
||||
|
||||
#if 0
|
||||
{
|
||||
char rx[512], buffer[512];
|
||||
int i,j;
|
||||
int blocks = file.size / 512;
|
||||
|
||||
FileSeek(&file, 0, SEEK_SET);
|
||||
|
||||
mist_memory_set_address(TOS_BASE_ADDRESS);
|
||||
|
||||
iprintf("Verifying: [");
|
||||
for(i=0;i<blocks;i++) {
|
||||
FileRead(&file, buffer);
|
||||
|
||||
mist_memory_read(rx, 256);
|
||||
|
||||
if(!(i & 7)) iprintf("+");
|
||||
|
||||
for(j=0;j<512;j++) {
|
||||
if(buffer[j] != rx[j]) {
|
||||
iprintf("Verify error block %d, byte %x\n", i, j);
|
||||
|
||||
iprintf("should be:\n");
|
||||
hexdump(buffer, 512, 0);
|
||||
|
||||
iprintf("is:\n");
|
||||
hexdump(rx, 512, 0);
|
||||
|
||||
// try to re-read to check whether read or write failed
|
||||
mist_memory_set_address(TOS_BASE_ADDRESS+i*512);
|
||||
mist_memory_read(rx, 256);
|
||||
|
||||
iprintf("re-read: %s\n", (buffer[j] != rx[j])?"failed":"ok");
|
||||
hexdump(rx, 512, 0);
|
||||
|
||||
|
||||
while(1);
|
||||
}
|
||||
}
|
||||
|
||||
if(i != blocks-1)
|
||||
FileNextSector(&file);
|
||||
}
|
||||
iprintf("]\n");
|
||||
}
|
||||
#endif
|
||||
DISKLED_OFF;
|
||||
|
||||
// upload cartridge
|
||||
if(FileOpen(&file,"CART IMG")) {
|
||||
int i;
|
||||
char buffer[512];
|
||||
|
||||
iprintf("CART.IMG:\n size = %d\n", file.size);
|
||||
|
||||
int blocks = file.size / 512;
|
||||
iprintf(" blocks = %d\n", blocks);
|
||||
|
||||
iprintf("Uploading: [");
|
||||
mist_memory_set_address(CART_BASE_ADDRESS);
|
||||
|
||||
DISKLED_ON;
|
||||
for(i=0;i<blocks;i++) {
|
||||
FileRead(&file, buffer);
|
||||
mist_memory_write(buffer, 256);
|
||||
|
||||
if(!(i & 7)) iprintf(".");
|
||||
|
||||
if(i != blocks-1)
|
||||
FileNextSector(&file);
|
||||
}
|
||||
DISKLED_OFF;
|
||||
iprintf("]\n");
|
||||
|
||||
iprintf("CART.IMG uploaded\r");
|
||||
} else {
|
||||
iprintf("Unable to find cart.img\n");
|
||||
|
||||
// erase that ram area to remove any previously uploaded
|
||||
// image
|
||||
mist_memory_set_address(CART_BASE_ADDRESS);
|
||||
mist_memory_set(0, 128*1024/2);
|
||||
}
|
||||
|
||||
// try to open both floppies
|
||||
int i;
|
||||
for(i=0;i<2;i++) {
|
||||
char name[] = "DISK_A ST ";
|
||||
name[5] = 'A'+i;
|
||||
|
||||
fileTYPE file;
|
||||
if(FileOpen(&file, name))
|
||||
tos_insert_disk(i, &file);
|
||||
}
|
||||
|
||||
tos_write("Booting ... ");
|
||||
|
||||
// let cpu run (release reset)
|
||||
mist_set_control(tos_system_ctrl);
|
||||
}
|
||||
|
||||
static unsigned long get_long(char *buffer, int offset) {
|
||||
unsigned long retval = 0;
|
||||
int i;
|
||||
|
||||
for(i=0;i<4;i++)
|
||||
retval = (retval << 8) + *(unsigned char*)(buffer+offset+i);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void tos_show_state() {
|
||||
static unsigned long mtimer = 0;
|
||||
|
||||
mist_get_dmastate();
|
||||
|
||||
#if 0
|
||||
if(CheckTimer(mtimer)) {
|
||||
mtimer = GetTimer(2000);
|
||||
|
||||
int i;
|
||||
char buffer[1024];
|
||||
|
||||
mist_memory_set_address(0);
|
||||
mist_memory_read(buffer, 64);
|
||||
hexdump(buffer, 128, 0);
|
||||
|
||||
// tos system varables are from $400
|
||||
mist_memory_set_address(0x400);
|
||||
mist_memory_read(buffer, 512);
|
||||
|
||||
iprintf("\n--- SYSTEM VARIABLES ---\n");
|
||||
iprintf("memvalid: $%lx (should be $752019F3)\n", get_long(buffer,0x20));
|
||||
iprintf("memcntrl: $%x (memory controller low nibble)\n", buffer[0x24]);
|
||||
iprintf("phystop: $%lx (Physical RAM top)\n", get_long(buffer,0x2e));
|
||||
iprintf("memval2: $%lx (should be $237698AA)\n", get_long(buffer,0x3a));
|
||||
iprintf("sshiftmd: $%x (Shadow shiftmd, LMH/012)\n", buffer[0x4c]);
|
||||
iprintf("_v_bas_ad: $%lx (Screen memory base)\n", get_long(buffer,0x4e));
|
||||
iprintf("_vbclock: $%lx (vbl counter)\n", get_long(buffer,0x62));
|
||||
iprintf("_dskbufp: $%lx (1k disk buffer)\n", get_long(buffer,0xc6));
|
||||
iprintf("_frclock: $%lx (frame counter)\n", get_long(buffer,0x66));
|
||||
iprintf("_hz_200: $%lx (Raw 200Hz timer)\n", get_long(buffer,0xba));
|
||||
iprintf("_sysbase: $%lx (begin of tos)\n", get_long(buffer,0xf2));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void tos_update_sysctrl(unsigned long n) {
|
||||
tos_system_ctrl = n;
|
||||
mist_set_control(tos_system_ctrl);
|
||||
}
|
||||
|
||||
char *tos_get_disk_name(char index) {
|
||||
static char buffer[13]; // local buffer to assemble file name (8+3+2)
|
||||
char *c;
|
||||
|
||||
if(!disk[index].file.size) {
|
||||
strcpy(buffer, "* no disk *");
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// copy and append nul
|
||||
strncpy(buffer, disk[index].file.name, 8);
|
||||
for(c=buffer+7;*c==' ';c--); c++;
|
||||
*c++ = '.';
|
||||
strncpy(c, disk[index].file.name+8, 3);
|
||||
for(c+=2;*c==' ';c--); c++;
|
||||
*c++='\0';
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char tos_disk_is_inserted(char index) {
|
||||
return (disk[index].file.size != 0);
|
||||
}
|
||||
|
||||
void tos_insert_disk(char i, fileTYPE *file) {
|
||||
iprintf("%c: eject\n", i+'A');
|
||||
|
||||
// toggle write protect bit to help tos detect a media change
|
||||
int wp_bit = (!i)?TOS_CONTROL_FDC_WR_PROT_A:TOS_CONTROL_FDC_WR_PROT_B;
|
||||
|
||||
// any disk ejected is "write protected" (as nothing covers the write protect mechanism)
|
||||
mist_set_control(tos_system_ctrl | wp_bit);
|
||||
|
||||
// first "eject" disk
|
||||
disk[i].file.size = 0;
|
||||
disk[i].sides = 1;
|
||||
disk[i].spt = 0;
|
||||
|
||||
// no new disk given?
|
||||
if(!file) return;
|
||||
|
||||
// open floppy
|
||||
disk[i].file = *file;
|
||||
iprintf("%c: insert %.11s\n", i+'A', disk[i].file.name);
|
||||
|
||||
// check image size and parameters
|
||||
|
||||
// check if image size suggests it's a two sided disk
|
||||
if(disk[i].file.size > 80*9*512)
|
||||
disk[i].sides = 2;
|
||||
|
||||
// try common sector/track values
|
||||
int s, t;
|
||||
for(s=9;s<=12;s++)
|
||||
for(t=80;t<=85;t++)
|
||||
if(512*s*t*disk[i].sides == disk[i].file.size)
|
||||
disk[i].spt = s;
|
||||
|
||||
if(!disk[i].spt) {
|
||||
iprintf("%c: image has unknown size\n", i+'A');
|
||||
|
||||
// todo: try to extract that info from the image itself
|
||||
|
||||
disk[i].file.size = 0;
|
||||
} else {
|
||||
// restore state of write protect bit
|
||||
tos_update_sysctrl(tos_system_ctrl);
|
||||
iprintf("%c: detected %d sides with %d sectors per track\n",
|
||||
i+'A', disk[i].sides, disk[i].spt);
|
||||
}
|
||||
}
|
||||
57
tos.h
Normal file
57
tos.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#ifndef TOS_H
|
||||
#define TOS_H
|
||||
|
||||
#include "fat.h"
|
||||
|
||||
// FPGA spi cmommands
|
||||
#define MIST_INVALID 0x00
|
||||
|
||||
// memory interface
|
||||
#define MIST_SET_ADDRESS 0x01
|
||||
#define MIST_WRITE_MEMORY 0x02
|
||||
#define MIST_READ_MEMORY 0x03
|
||||
#define MIST_SET_CONTROL 0x04
|
||||
#define MIST_GET_DMASTATE 0x05 // reads state of dma and floppy controller
|
||||
#define MIST_ACK_DMA 0x06 // acknowledges a dma command
|
||||
|
||||
// tos sysconfig bits:
|
||||
// 0 - RESET
|
||||
// 1-3 - Memory configuration
|
||||
// 4-5 - CPU configuration
|
||||
// 6-7 - Floppy A+B write protection
|
||||
// 8 - Color/Monochrome mode
|
||||
|
||||
// memory configurations (0x02/0x04/0x08)
|
||||
// (currently 4MB are fixed and cannot be changed)
|
||||
#define TOS_MEMCONFIG_512K (0<<1) // not yet supported
|
||||
#define TOS_MEMCONFIG_1M (1<<1) // not yet supported
|
||||
#define TOS_MEMCONFIG_2M (2<<1) // not yet supported
|
||||
#define TOS_MEMCONFIG_4M (3<<1) // not yet supported
|
||||
#define TOS_MEMCONFIG_8M (4<<1)
|
||||
#define TOS_MEMCONFIG_14M (5<<1)
|
||||
#define TOS_MEMCONFIG_RES0 (6<<1) // reserved
|
||||
#define TOS_MEMCONFIG_RES1 (7<<1) // reserved
|
||||
|
||||
// cpu configurations (0x10/0x20)
|
||||
#define TOS_CPUCONFIG_68000 (0<<4)
|
||||
#define TOS_CPUCONFIG_68010 (1<<4)
|
||||
#define TOS_CPUCONFIG_RESERVED (2<<4)
|
||||
#define TOS_CPUCONFIG_68020 (3<<4)
|
||||
|
||||
// control bits (all control bits have unknown state after core startup)
|
||||
#define TOS_CONTROL_CPU_RESET 0x0001
|
||||
#define TOS_CONTROL_FDC_WR_PROT_A 0x0040
|
||||
#define TOS_CONTROL_FDC_WR_PROT_B 0x0080
|
||||
#define TOS_CONTROL_VIDEO_COLOR 0x0100 // input to mfp
|
||||
#define TOS_CONTROL_PAL50HZ 0x0200 // display pal at 50hz (56 hz otherwise)
|
||||
|
||||
extern unsigned long tos_system_ctrl;
|
||||
|
||||
void tos_upload();
|
||||
void tos_show_state();
|
||||
void tos_update_sysctrl(unsigned long);
|
||||
char *tos_get_disk_name(char);
|
||||
char tos_disk_is_inserted(char index);
|
||||
void tos_insert_disk(char i, fileTYPE *file);
|
||||
|
||||
#endif
|
||||
372
usb/hid.c
Normal file
372
usb/hid.c
Normal file
@@ -0,0 +1,372 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "usb.h"
|
||||
#include "max3421e.h"
|
||||
#include "timer.h"
|
||||
#include "../user_io.h"
|
||||
|
||||
static unsigned char kbd_led_state = 0; // default: all leds off
|
||||
|
||||
static void hexdump(void *data, int size) {
|
||||
int i,n = 0, b2c;
|
||||
char *ptr = data;
|
||||
|
||||
if(!size) return;
|
||||
|
||||
while(size>0) {
|
||||
iprintf("%04x: ", n);
|
||||
|
||||
b2c = (size>16)?16:size;
|
||||
|
||||
for(i=0;i<b2c;i++)
|
||||
iprintf("%02x ", 0xff&ptr[i]);
|
||||
|
||||
iprintf(" ");
|
||||
|
||||
for(i=0;i<(16-b2c);i++)
|
||||
iprintf(" ");
|
||||
|
||||
for(i=0;i<b2c;i++)
|
||||
iprintf("%c", isprint(ptr[i])?ptr[i]:'.');
|
||||
|
||||
iprintf("\n");
|
||||
|
||||
ptr += b2c;
|
||||
size -= b2c;
|
||||
n += b2c;
|
||||
}
|
||||
}
|
||||
|
||||
//get HID report descriptor
|
||||
static uint8_t hid_get_report_descr(usb_device_t *dev, uint8_t iface, uint16_t size) {
|
||||
iprintf("%s(%x, if=%d, size=%d)\n", __FUNCTION__, dev->bAddress, iface, size);
|
||||
|
||||
uint8_t buf[size];
|
||||
uint8_t rcode = usb_ctrl_req( dev, HID_REQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00,
|
||||
HID_DESCRIPTOR_REPORT, iface, size, size, buf, NULL);
|
||||
|
||||
if(!rcode)
|
||||
hexdump(buf, size);
|
||||
|
||||
return rcode;
|
||||
}
|
||||
|
||||
static uint8_t hid_set_idle(usb_device_t *dev, uint8_t iface, uint8_t reportID, uint8_t duration ) {
|
||||
iprintf("%s(%x, if=%d id=%d, dur=%d)\n", __FUNCTION__, dev->bAddress, iface, reportID, duration);
|
||||
|
||||
return( usb_ctrl_req( dev, HID_REQ_HIDOUT, HID_REQUEST_SET_IDLE, reportID,
|
||||
duration, iface, 0x0000, 0x0000, NULL, NULL ));
|
||||
}
|
||||
|
||||
static uint8_t hid_set_protocol(usb_device_t *dev, uint8_t iface, uint8_t protocol) {
|
||||
iprintf("%s(%x, if=%d proto=%d)\n", __FUNCTION__, dev->bAddress, iface, protocol);
|
||||
|
||||
return( usb_ctrl_req( dev, HID_REQ_HIDOUT, HID_REQUEST_SET_PROTOCOL, protocol,
|
||||
0x00, iface, 0x0000, 0x0000, NULL, NULL ));
|
||||
}
|
||||
|
||||
static uint8_t hid_set_report(usb_device_t *dev, uint8_t iface, uint8_t report_type, uint8_t report_id,
|
||||
uint16_t nbytes, uint8_t* dataptr ) {
|
||||
// iprintf("%s(%x, if=%d data=%x)\n", __FUNCTION__, dev->bAddress, iface, dataptr[0]);
|
||||
|
||||
return( usb_ctrl_req(dev, HID_REQ_HIDOUT, HID_REQUEST_SET_REPORT, report_id,
|
||||
report_type, iface, nbytes, nbytes, dataptr, NULL ));
|
||||
}
|
||||
|
||||
/* todo: handle parsing in chunks */
|
||||
static uint8_t usb_hid_parse_conf(usb_device_t *dev, uint8_t conf, uint16_t len) {
|
||||
usb_hid_info_t *info = &(dev->hid_info);
|
||||
uint8_t rcode;
|
||||
bool isGoodInterface = false;
|
||||
|
||||
union buf_u {
|
||||
usb_configuration_descriptor_t conf_desc;
|
||||
usb_interface_descriptor_t iface_desc;
|
||||
usb_endpoint_descriptor_t ep_desc;
|
||||
usb_hid_descriptor_t hid_desc;
|
||||
uint8_t raw[len];
|
||||
} buf, *p;
|
||||
|
||||
// usb_interface_descriptor
|
||||
|
||||
if(rcode = usb_get_conf_descr(dev, len, conf, &buf.conf_desc))
|
||||
return rcode;
|
||||
|
||||
/* scan through all descriptors */
|
||||
p = &buf;
|
||||
while(len > 0) {
|
||||
|
||||
switch(p->conf_desc.bDescriptorType) {
|
||||
case USB_DESCRIPTOR_CONFIGURATION:
|
||||
iprintf("conf descriptor size %d\n", p->conf_desc.bLength);
|
||||
// we already had this, so we simply ignore it
|
||||
break;
|
||||
|
||||
case USB_DESCRIPTOR_INTERFACE:
|
||||
isGoodInterface = false;
|
||||
iprintf("iface descriptor size %d\n", p->iface_desc.bLength);
|
||||
|
||||
/* check the interface descriptors for supported class */
|
||||
|
||||
// only HID interfaces are supported
|
||||
if(p->iface_desc.bInterfaceClass == USB_CLASS_HID) {
|
||||
puts("iface is HID");
|
||||
|
||||
if(info->bNumIfaces < MAX_IFACES) {
|
||||
// ok, let's use this interface
|
||||
isGoodInterface = true;
|
||||
|
||||
info->iface_info[info->bNumIfaces].iface_idx = p->iface_desc.bInterfaceNumber;
|
||||
info->iface_info[info->bNumIfaces].has_boot_mode = false;
|
||||
info->iface_info[info->bNumIfaces].device_type = HID_DEVICE_UNKNOWN;
|
||||
|
||||
if(p->iface_desc.bInterfaceSubClass == HID_BOOT_INTF_SUBCLASS) {
|
||||
iprintf("Iface %d is Boot sub class\n", info->bNumIfaces);
|
||||
info->iface_info[info->bNumIfaces].has_boot_mode = true;
|
||||
|
||||
// enable boot mode
|
||||
hid_set_protocol(dev, info->iface_info[info->bNumIfaces].iface_idx, HID_BOOT_PROTOCOL);
|
||||
}
|
||||
|
||||
switch(p->iface_desc.bInterfaceProtocol) {
|
||||
case HID_PROTOCOL_NONE:
|
||||
iprintf("HID protocol is NONE\n");
|
||||
break;
|
||||
|
||||
case HID_PROTOCOL_KEYBOARD:
|
||||
iprintf("HID protocol is KEYBOARD\n");
|
||||
info->iface_info[info->bNumIfaces].device_type = HID_DEVICE_KEYBOARD;
|
||||
// hid_set_report(dev, info->iface_info[info->bNumIfaces].iface_idx, 2, 0, 1, &kbd_led_state);
|
||||
break;
|
||||
|
||||
case HID_PROTOCOL_MOUSE:
|
||||
iprintf("HID protocol is MOUSE\n");
|
||||
info->iface_info[info->bNumIfaces].device_type = HID_DEVICE_MOUSE;
|
||||
break;
|
||||
|
||||
default:
|
||||
iprintf("HID protocol is %d\n", p->iface_desc.bInterfaceProtocol);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_DESCRIPTOR_ENDPOINT:
|
||||
iprintf("endpoint descriptor size %d\n", p->ep_desc.bLength);
|
||||
|
||||
if(isGoodInterface) {
|
||||
|
||||
// only interrupt in endpoints are supported
|
||||
if ((p->ep_desc.bmAttributes & 0x03) == 3 && (p->ep_desc.bEndpointAddress & 0x80) == 0x80) {
|
||||
iprintf("endpint %d, interval = %dms\n",
|
||||
p->ep_desc.bEndpointAddress & 0x0F, p->ep_desc.bInterval);
|
||||
|
||||
// Fill in the endpoint info structure
|
||||
uint8_t epidx = info->bNumIfaces;
|
||||
info->ep[epidx].epAddr = (p->ep_desc.bEndpointAddress & 0x0F);
|
||||
info->ep[epidx].maxPktSize = p->ep_desc.wMaxPacketSize[0];
|
||||
info->ep[epidx].epAttribs = 0;
|
||||
info->ep[epidx].bmNakPower = USB_NAK_NOWAIT;
|
||||
info->bNumIfaces++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HID_DESCRIPTOR_HID:
|
||||
iprintf("hid descriptor size %d\n", p->ep_desc.bLength);
|
||||
|
||||
if(isGoodInterface) {
|
||||
// we need a report descriptor
|
||||
if(p->hid_desc.bDescrType == HID_DESCRIPTOR_REPORT) {
|
||||
uint16_t len = p->hid_desc.wDescriptorLength[0] +
|
||||
256 * p->hid_desc.wDescriptorLength[1];
|
||||
iprintf(" -> report descriptor size = %d\n", len);
|
||||
|
||||
info->iface_info[info->bNumIfaces].report_size = len;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
iprintf("unsupported descriptor type %d size %d\n", p->raw[1], p->raw[0]);
|
||||
}
|
||||
|
||||
// advance to next descriptor
|
||||
len -= p->conf_desc.bLength;
|
||||
p = (union buf_u*)(p->raw + p->conf_desc.bLength);
|
||||
}
|
||||
|
||||
if(len != 0) {
|
||||
iprintf("URGS, underrun: %d\n", len);
|
||||
return USB_ERROR_CONFIGURAION_SIZE_MISMATCH;
|
||||
}
|
||||
|
||||
iprintf("done\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t usb_hid_init(usb_device_t *dev) {
|
||||
iprintf("%s()\n", __FUNCTION__);
|
||||
|
||||
iprintf("init with address %x\n", dev->bAddress);
|
||||
|
||||
uint8_t rcode;
|
||||
uint8_t i;
|
||||
|
||||
usb_hid_info_t *info = &(dev->hid_info);
|
||||
|
||||
union {
|
||||
usb_device_descriptor_t dev_desc;
|
||||
usb_configuration_descriptor_t conf_desc;
|
||||
} buf;
|
||||
|
||||
// reset status
|
||||
info->qNextPollTime = 0;
|
||||
info->bPollEnable = false;
|
||||
info->bNumIfaces = 0;
|
||||
|
||||
for(i=0;i<MAX_IFACES;i++) {
|
||||
info->ep[i].epAddr = i;
|
||||
info->ep[i].maxPktSize = 8;
|
||||
info->ep[i].epAttribs = 0;
|
||||
info->ep[i].bmNakPower = USB_NAK_MAX_POWER;
|
||||
}
|
||||
|
||||
// try to re-read full device descriptor from newly assigned address
|
||||
if(rcode = usb_get_dev_descr( dev, sizeof(usb_device_descriptor_t), &buf.dev_desc )) {
|
||||
puts("failed to get device descriptor");
|
||||
return rcode;
|
||||
}
|
||||
|
||||
uint8_t num_of_conf = buf.dev_desc.bNumConfigurations;
|
||||
iprintf("number of configurations: %d\n", num_of_conf);
|
||||
|
||||
for(i=0; i<num_of_conf; i++) {
|
||||
if(rcode = usb_get_conf_descr(dev, sizeof(usb_configuration_descriptor_t), i, &buf.conf_desc))
|
||||
return rcode;
|
||||
|
||||
iprintf("conf descriptor %d has total size %d\n", i, buf.conf_desc.wTotalLength);
|
||||
|
||||
// extract number of interfaces
|
||||
iprintf("number of interfaces: %d\n", buf.conf_desc.bNumInterfaces);
|
||||
|
||||
// parse directly if it already fitted completely into the buffer
|
||||
usb_hid_parse_conf(dev, i, buf.conf_desc.wTotalLength);
|
||||
}
|
||||
|
||||
// check if we found valid hid interfaces
|
||||
if(!info->bNumIfaces) {
|
||||
puts("no hid interfaces found");
|
||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
// Set Configuration Value
|
||||
iprintf("conf value = %d\n", buf.conf_desc.bConfigurationValue);
|
||||
rcode = usb_set_conf(dev, buf.conf_desc.bConfigurationValue);
|
||||
|
||||
// process all supported interfaces
|
||||
for(i=0; i<info->bNumIfaces; i++) {
|
||||
rcode = hid_get_report_descr(dev,
|
||||
info->iface_info[i].iface_idx, info->iface_info[i].report_size);
|
||||
if (rcode)
|
||||
return rcode;
|
||||
|
||||
rcode = hid_set_idle(dev, info->iface_info[i].iface_idx, 0, 0);
|
||||
if (rcode && rcode != hrSTALL)
|
||||
return rcode;
|
||||
|
||||
}
|
||||
|
||||
puts("HID configured");
|
||||
|
||||
// update leds
|
||||
for(i=0;i<MAX_IFACES;i++)
|
||||
if(dev->hid_info.iface_info[i].device_type == HID_DEVICE_KEYBOARD)
|
||||
hid_set_report(dev, dev->hid_info.iface_info[i].iface_idx, 2, 0, 1, &kbd_led_state);
|
||||
|
||||
info->bPollEnable = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t usb_hid_release(usb_device_t *dev) {
|
||||
puts(__FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t usb_hid_poll(usb_device_t *dev) {
|
||||
usb_hid_info_t *info = &(dev->hid_info);
|
||||
|
||||
if (!info->bPollEnable)
|
||||
return 0;
|
||||
|
||||
if (info->qNextPollTime <= timer_get_msec()) {
|
||||
int8_t i;
|
||||
for(i=0;i<info->bNumIfaces;i++) {
|
||||
// iprintf("poll %d...\n", info->ep[i].epAddr);
|
||||
|
||||
uint16_t read = info->ep[i].maxPktSize;
|
||||
uint8_t buf[32];
|
||||
uint8_t rcode =
|
||||
usb_in_transfer(dev, &(info->ep[i]), &read, buf);
|
||||
|
||||
if (rcode) {
|
||||
if (rcode != hrNAK)
|
||||
iprintf("%s() error: %d %d\n", __FUNCTION__, rcode, timer_get_msec());
|
||||
// else
|
||||
// puts("nak");
|
||||
} else {
|
||||
|
||||
// iprintf("interface %d: received %d bytes\n", i, read);
|
||||
|
||||
// successfully received some bytes
|
||||
if(info->iface_info[i].has_boot_mode) {
|
||||
if(info->iface_info[i].device_type == HID_DEVICE_MOUSE) {
|
||||
// boot mouse needs at least three bytes
|
||||
if(read >= 3) {
|
||||
// forward all three bytes to the user_io layer
|
||||
user_io_mouse(buf[0], buf[1], buf[2]);
|
||||
}
|
||||
}
|
||||
|
||||
if(info->iface_info[i].device_type == HID_DEVICE_KEYBOARD) {
|
||||
// boot kbd needs at least eight bytes
|
||||
if(read >= 8) {
|
||||
user_io_kbd(buf[0], buf+2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info->qNextPollTime = timer_get_msec() + 20; // poll 50 times a second
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hid_set_kbd_led(unsigned char led, bool on) {
|
||||
// check if led state has changed
|
||||
if( (on && !(kbd_led_state&led)) || (!on && (kbd_led_state&led))) {
|
||||
if(on) kbd_led_state |= led;
|
||||
else kbd_led_state &= ~led;
|
||||
|
||||
// search for all keyboard interfaces on all hid devices
|
||||
usb_device_t *dev = usb_get_devices();
|
||||
int i;
|
||||
for(i=0;i<USB_NUMDEVICES;i++) {
|
||||
if(dev[i].bAddress && (dev[i].class == &usb_hid_class)) {
|
||||
// search for keyboard interfaces
|
||||
int j;
|
||||
for(j=0;j<MAX_IFACES;j++)
|
||||
if(dev[i].hid_info.iface_info[j].device_type == HID_DEVICE_KEYBOARD)
|
||||
hid_set_report(dev+i, dev[i].hid_info.iface_info[j].iface_idx, 2, 0, 1, &kbd_led_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const usb_device_class_config_t usb_hid_class = {
|
||||
usb_hid_init, usb_hid_release, usb_hid_poll };
|
||||
|
||||
79
usb/hid.h
Normal file
79
usb/hid.h
Normal file
@@ -0,0 +1,79 @@
|
||||
#ifndef HID_H
|
||||
#define HID_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define HID_LED_NUM_LOCK 0x01
|
||||
#define HID_LED_CAPS_LOCK 0x02
|
||||
#define HID_LED_SCROLL_LOCK 0x04
|
||||
|
||||
/* HID constants. Not part of chapter 9 */
|
||||
/* Class-Specific Requests */
|
||||
#define HID_REQUEST_GET_REPORT 0x01
|
||||
#define HID_REQUEST_GET_IDLE 0x02
|
||||
#define HID_REQUEST_GET_PROTOCOL 0x03
|
||||
#define HID_REQUEST_SET_REPORT 0x09
|
||||
#define HID_REQUEST_SET_IDLE 0x0A
|
||||
#define HID_REQUEST_SET_PROTOCOL 0x0B
|
||||
|
||||
#define HID_DESCRIPTOR_HID 0x21
|
||||
#define HID_DESCRIPTOR_REPORT 0x22
|
||||
#define HID_DESRIPTOR_PHY 0x23
|
||||
|
||||
/* Protocol Selection */
|
||||
#define HID_BOOT_PROTOCOL 0x00
|
||||
#define HID_RPT_PROTOCOL 0x01
|
||||
|
||||
/* HID Interface Class SubClass Codes */
|
||||
#define HID_BOOT_INTF_SUBCLASS 0x01
|
||||
|
||||
#define HID_PROTOCOL_NONE 0x00
|
||||
#define HID_PROTOCOL_KEYBOARD 0x01
|
||||
#define HID_PROTOCOL_MOUSE 0x02
|
||||
|
||||
#define HID_REQ_HIDREPORT USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_INTERFACE
|
||||
#define HID_REQ_HIDOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
||||
|
||||
#define MAX_IFACES 2 // max supported interfaces per device. 2 to support kbd/mouse combos
|
||||
|
||||
#define HID_DEVICE_UNKNOWN 0
|
||||
#define HID_DEVICE_MOUSE 1
|
||||
#define HID_DEVICE_KEYBOARD 2
|
||||
|
||||
typedef struct {
|
||||
uint8_t iface_idx;
|
||||
uint16_t report_size;
|
||||
|
||||
uint8_t device_type;
|
||||
bool has_boot_mode; // device supports boot mode
|
||||
|
||||
} usb_hid_iface_info_t;
|
||||
|
||||
typedef struct {
|
||||
ep_t ep[MAX_IFACES]; // interrupt endpoint info structure
|
||||
uint32_t qNextPollTime; // next poll time
|
||||
bool bPollEnable; // poll enable flag
|
||||
uint8_t bNumIfaces;
|
||||
|
||||
usb_hid_iface_info_t iface_info[MAX_IFACES];
|
||||
|
||||
} usb_hid_info_t;
|
||||
|
||||
/* HID descriptor */
|
||||
typedef struct {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint16_t bcdHID; // HID class specification release
|
||||
uint8_t bCountryCode;
|
||||
uint8_t bNumDescriptors; // Number of additional class specific descriptors
|
||||
uint8_t bDescrType; // Type of class descriptor
|
||||
uint8_t wDescriptorLength[2]; // Total size of the Report descriptor
|
||||
} __attribute__((packed)) usb_hid_descriptor_t;
|
||||
|
||||
// interface to usb core
|
||||
extern const usb_device_class_config_t usb_hid_class;
|
||||
|
||||
void hid_set_kbd_led(unsigned char led, bool on);
|
||||
|
||||
#endif // HID_H
|
||||
283
usb/hub.c
Normal file
283
usb/hub.c
Normal file
@@ -0,0 +1,283 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "usb.h"
|
||||
#include "timer.h"
|
||||
|
||||
static uint8_t usb_hub_clear_hub_feature(usb_device_t *dev, uint8_t fid ) {
|
||||
return( usb_ctrl_req( dev, USB_HUB_REQ_CLEAR_HUB_FEATURE,
|
||||
USB_REQUEST_CLEAR_FEATURE, fid, 0, 0, 0, 0, NULL, NULL ));
|
||||
}
|
||||
|
||||
// Clear Port Feature
|
||||
static uint8_t usb_hub_clear_port_feature(usb_device_t *dev, uint8_t fid, uint8_t port, uint8_t sel ) {
|
||||
return( usb_ctrl_req( dev , USB_HUB_REQ_CLEAR_PORT_FEATURE,
|
||||
USB_REQUEST_CLEAR_FEATURE, fid, 0, ((0x0000|port)|(sel<<8)), 0, 0, NULL, NULL ));
|
||||
}
|
||||
// Get Hub Descriptor
|
||||
static uint8_t usb_hub_get_hub_descriptor(usb_device_t *dev, uint8_t index,
|
||||
uint16_t nbytes, usb_hub_descriptor_t *dataptr ) {
|
||||
return( usb_ctrl_req( dev, USB_HUB_REQ_GET_HUB_DESCRIPTOR,
|
||||
USB_REQUEST_GET_DESCRIPTOR, index, 0x29, 0, nbytes, nbytes,
|
||||
(uint8_t*)dataptr, NULL ));
|
||||
}
|
||||
|
||||
// Set Port Feature
|
||||
static uint8_t usb_hub_set_port_feature(usb_device_t *dev, uint8_t fid, uint8_t port, uint8_t sel ) {
|
||||
return( usb_ctrl_req( dev, USB_HUB_REQ_SET_PORT_FEATURE,
|
||||
USB_REQUEST_SET_FEATURE, fid, 0, (((0x0000|sel)<<8)|port), 0, 0, NULL, NULL ));
|
||||
}
|
||||
|
||||
// Get Port Status
|
||||
static uint8_t usb_hub_get_port_status(usb_device_t *dev, uint8_t port, uint16_t nbytes, uint8_t* dataptr ) {
|
||||
return( usb_ctrl_req( dev, USB_HUB_REQ_GET_PORT_STATUS,
|
||||
USB_REQUEST_GET_STATUS, 0, 0, port, nbytes, nbytes, dataptr, NULL ));
|
||||
}
|
||||
|
||||
static uint8_t usb_hub_init(usb_device_t *dev) {
|
||||
iprintf("%s()\n", __FUNCTION__);
|
||||
|
||||
uint8_t rcode;
|
||||
uint8_t i;
|
||||
|
||||
usb_hub_info_t *info = &(dev->hub_info);
|
||||
|
||||
union {
|
||||
usb_device_descriptor_t dev_desc;
|
||||
usb_configuration_descriptor_t conf_desc;
|
||||
usb_hub_descriptor_t hub_desc;
|
||||
} buf;
|
||||
|
||||
// reset status
|
||||
info->bNbrPorts = 0;
|
||||
info->qNextPollTime = 0;
|
||||
info->bPollEnable = false;
|
||||
|
||||
info->ep.epAddr = 1;
|
||||
info->ep.maxPktSize = 8; //kludge
|
||||
info->ep.epAttribs = 0;
|
||||
info->ep.bmNakPower = USB_NAK_NOWAIT;
|
||||
|
||||
rcode = usb_get_dev_descr( dev, 8, &buf.dev_desc );
|
||||
if( rcode ) {
|
||||
puts("failed to get device descriptor 1");
|
||||
return rcode;
|
||||
}
|
||||
|
||||
// Extract device class from device descriptor
|
||||
// If device class is not a hub return
|
||||
if (buf.dev_desc.bDeviceClass != USB_CLASS_HUB) {
|
||||
puts("not a hub!");
|
||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
// try to re-read full device descriptor from newly assigned address
|
||||
if(rcode = usb_get_dev_descr( dev, sizeof(usb_device_descriptor_t), &buf.dev_desc )) {
|
||||
puts("failed to get device descriptor 2");
|
||||
return rcode;
|
||||
}
|
||||
|
||||
// Get hub descriptor
|
||||
rcode = usb_hub_get_hub_descriptor(dev, 0, 8, &buf.hub_desc);
|
||||
|
||||
if (rcode) {
|
||||
puts("failed to get hub descriptor");
|
||||
return rcode;
|
||||
}
|
||||
|
||||
// Save number of ports for future use
|
||||
info->bNbrPorts = buf.hub_desc.bNbrPorts;
|
||||
|
||||
// Read configuration Descriptor in Order To Obtain Proper Configuration Value
|
||||
rcode = usb_get_conf_descr(dev, sizeof(usb_configuration_descriptor_t), 0, &buf.conf_desc);
|
||||
if (rcode) {
|
||||
puts("failed to read configuration descriptor");
|
||||
return rcode;
|
||||
}
|
||||
|
||||
// Set Configuration Value
|
||||
rcode = usb_set_conf(dev, buf.conf_desc.bConfigurationValue);
|
||||
if (rcode) {
|
||||
iprintf("failed to set configuration to %d\n", buf.conf_desc.bConfigurationValue);
|
||||
return rcode;
|
||||
}
|
||||
|
||||
// Power on all ports
|
||||
for (i=1; i<=info->bNbrPorts; i++)
|
||||
usb_hub_set_port_feature(dev, HUB_FEATURE_PORT_POWER, i, 0); // HubPortPowerOn(i);
|
||||
|
||||
if(!dev->parent)
|
||||
usb_SetHubPreMask();
|
||||
|
||||
info->bPollEnable = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t usb_hub_release(usb_device_t *dev) {
|
||||
puts(__FUNCTION__);
|
||||
|
||||
// root hub unplugged
|
||||
if(!dev->parent)
|
||||
usb_ResetHubPreMask();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usb_hub_show_port_status(uint8_t port, uint16_t status, uint16_t changed) {
|
||||
iprintf("Status of port %d:\n", port);
|
||||
|
||||
if(status & USB_HUB_PORT_STATUS_PORT_CONNECTION) puts(" connected");
|
||||
if(status & USB_HUB_PORT_STATUS_PORT_ENABLE) puts(" enabled");
|
||||
if(status & USB_HUB_PORT_STATUS_PORT_SUSPEND) puts(" suspended");
|
||||
if(status & USB_HUB_PORT_STATUS_PORT_OVER_CURRENT) puts(" over current");
|
||||
if(status & USB_HUB_PORT_STATUS_PORT_RESET) puts(" reset");
|
||||
if(status & USB_HUB_PORT_STATUS_PORT_POWER) puts(" powered");
|
||||
if(status & USB_HUB_PORT_STATUS_PORT_LOW_SPEED) puts(" low speed");
|
||||
if(status & USB_HUB_PORT_STATUS_PORT_HIGH_SPEED) puts(" high speed");
|
||||
if(status & USB_HUB_PORT_STATUS_PORT_TEST) puts(" test");
|
||||
if(status & USB_HUB_PORT_STATUS_PORT_INDICATOR) puts(" indicator");
|
||||
|
||||
iprintf("Changes on port %d:\n", port);
|
||||
if(changed & USB_HUB_PORT_STATUS_PORT_CONNECTION) puts(" connected");
|
||||
if(changed & USB_HUB_PORT_STATUS_PORT_ENABLE) puts(" enabled");
|
||||
if(changed & USB_HUB_PORT_STATUS_PORT_SUSPEND) puts(" suspended");
|
||||
if(changed & USB_HUB_PORT_STATUS_PORT_OVER_CURRENT) puts(" over current");
|
||||
if(changed & USB_HUB_PORT_STATUS_PORT_RESET) puts(" reset");
|
||||
}
|
||||
|
||||
static uint8_t usb_hub_port_status_change(usb_device_t *dev, uint8_t port, hub_event_t evt) {
|
||||
usb_hub_info_t *info = &(dev->hub_info);
|
||||
|
||||
iprintf("status change on port %d, 0x%x\n", port, evt.bmEvent);
|
||||
usb_hub_show_port_status(port, evt.bmStatus, evt.bmChange);
|
||||
|
||||
static bool bResetInitiated = false;
|
||||
|
||||
switch (evt.bmEvent) {
|
||||
// Device connected event
|
||||
case USB_HUB_PORT_EVENT_CONNECT:
|
||||
case USB_HUB_PORT_EVENT_LS_CONNECT:
|
||||
iprintf(" dev %x: port %d connect!\n", dev->bAddress, port);
|
||||
|
||||
if (bResetInitiated) {
|
||||
iprintf("reset already in progress\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// timer_delay_msec(100);
|
||||
|
||||
iprintf("resetting port %d\n", port);
|
||||
usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_ENABLE, port, 0);
|
||||
usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_CONNECTION, port, 0);
|
||||
usb_hub_set_port_feature(dev, HUB_FEATURE_PORT_RESET, port, 0);
|
||||
bResetInitiated = true;
|
||||
return HUB_ERROR_PORT_HAS_BEEN_RESET;
|
||||
|
||||
// Device disconnected event
|
||||
case USB_HUB_PORT_EVENT_DISCONNECT:
|
||||
iprintf(" port %d disconnect!\n", port);
|
||||
|
||||
usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_ENABLE, port, 0);
|
||||
usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_CONNECTION, port, 0);
|
||||
bResetInitiated = false;
|
||||
|
||||
usb_release_device(dev->bAddress, port);
|
||||
|
||||
return 0;
|
||||
|
||||
// Reset complete event
|
||||
case USB_HUB_PORT_EVENT_RESET_COMPLETE:
|
||||
case USB_HUB_PORT_EVENT_LS_RESET_COMPLETE:
|
||||
iprintf(" port %d reset complete!\n", port);
|
||||
usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_RESET, port, 0);
|
||||
usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_CONNECTION, port, 0);
|
||||
|
||||
usb_configure(dev->bAddress, port,
|
||||
(evt.bmStatus & USB_HUB_PORT_STATUS_PORT_LOW_SPEED)!=0 );
|
||||
|
||||
bResetInitiated = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t usb_hub_check_hub_status(usb_device_t *dev, uint8_t ports) {
|
||||
usb_hub_info_t *info = &(dev->hub_info);
|
||||
|
||||
uint8_t rcode;
|
||||
uint8_t buf[8];
|
||||
uint16_t read = 1;
|
||||
|
||||
// iprintf("%s(addr=%x)\n", __FUNCTION__, addr);
|
||||
rcode = usb_in_transfer(dev, &(info->ep), &read, buf);
|
||||
if(rcode)
|
||||
return rcode;
|
||||
|
||||
uint8_t port, mask;
|
||||
for(port=1,mask=0x02; port<8; mask<<=1, port++) {
|
||||
if (buf[0] & mask) {
|
||||
hub_event_t evt;
|
||||
evt.bmEvent = 0;
|
||||
|
||||
// TODO XXXX: try sizeof(evt.evtBuff)
|
||||
rcode = usb_hub_get_port_status(dev, port, 4, evt.evtBuff);
|
||||
|
||||
if (rcode)
|
||||
continue;
|
||||
|
||||
rcode = usb_hub_port_status_change(dev, port, evt);
|
||||
|
||||
if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
|
||||
return 0;
|
||||
|
||||
if (rcode)
|
||||
return rcode;
|
||||
}
|
||||
} // for
|
||||
|
||||
for (port=1; port<=ports; port++) {
|
||||
hub_event_t evt;
|
||||
evt.bmEvent = 0;
|
||||
|
||||
rcode = usb_hub_get_port_status(dev, port, 4, evt.evtBuff);
|
||||
|
||||
if (rcode)
|
||||
continue;
|
||||
|
||||
if ((evt.bmStatus & USB_HUB_PORT_STATE_CHECK_DISABLED) != USB_HUB_PORT_STATE_DISABLED)
|
||||
continue;
|
||||
|
||||
// Emulate connection event for the port
|
||||
evt.bmChange |= USB_HUB_PORT_STATUS_PORT_CONNECTION;
|
||||
|
||||
rcode = usb_hub_port_status_change(dev, port, evt);
|
||||
|
||||
if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
|
||||
return 0;
|
||||
|
||||
if (rcode)
|
||||
return rcode;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t usb_hub_poll(usb_device_t *dev) {
|
||||
usb_hub_info_t *info = &(dev->hub_info);
|
||||
|
||||
uint8_t rcode = 0;
|
||||
|
||||
if (!info->bPollEnable)
|
||||
return 0;
|
||||
|
||||
if (info->qNextPollTime <= timer_get_msec()) {
|
||||
rcode = usb_hub_check_hub_status(dev, info->bNbrPorts);
|
||||
info->qNextPollTime = timer_get_msec() + 100; // poll 10 times a second
|
||||
}
|
||||
|
||||
return rcode;
|
||||
}
|
||||
|
||||
const usb_device_class_config_t usb_hub_class = {
|
||||
usb_hub_init, usb_hub_release, usb_hub_poll };
|
||||
|
||||
109
usb/hub.h
Normal file
109
usb/hub.h
Normal file
@@ -0,0 +1,109 @@
|
||||
#ifndef HUB_H
|
||||
#define HUB_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t bNbrPorts; // number of ports
|
||||
uint32_t qNextPollTime; // next poll time
|
||||
bool bPollEnable; // poll enable flag
|
||||
ep_t ep; // interrupt endpoint info structure
|
||||
} usb_hub_info_t;
|
||||
|
||||
// Hub Requests
|
||||
#define USB_HUB_REQ_CLEAR_HUB_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
|
||||
#define USB_HUB_REQ_CLEAR_PORT_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
|
||||
#define USB_HUB_REQ_CLEAR_TT_BUFFER USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
|
||||
#define USB_HUB_REQ_GET_HUB_DESCRIPTOR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
|
||||
#define USB_HUB_REQ_GET_HUB_STATUS USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
|
||||
#define USB_HUB_REQ_GET_PORT_STATUS USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
|
||||
#define USB_HUB_REQ_RESET_TT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
|
||||
#define USB_HUB_REQ_SET_HUB_DESCRIPTOR USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
|
||||
#define USB_HUB_REQ_SET_HUB_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
|
||||
#define USB_HUB_REQ_SET_PORT_FEATURE USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
|
||||
#define USB_HUB_REQ_GET_TT_STATE USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
|
||||
#define USB_HUB_REQ_STOP_TT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
|
||||
|
||||
// Hub Features
|
||||
#define HUB_FEATURE_C_HUB_LOCAL_POWER 0
|
||||
#define HUB_FEATURE_C_HUB_OVER_CURRENT 1
|
||||
|
||||
#define HUB_FEATURE_PORT_CONNECTION 0
|
||||
#define HUB_FEATURE_PORT_ENABLE 1
|
||||
#define HUB_FEATURE_PORT_SUSPEND 2
|
||||
#define HUB_FEATURE_PORT_OVER_CURRENT 3
|
||||
#define HUB_FEATURE_PORT_RESET 4
|
||||
#define HUB_FEATURE_PORT_POWER 8
|
||||
#define HUB_FEATURE_PORT_LOW_SPEED 9
|
||||
#define HUB_FEATURE_C_PORT_CONNECTION 16
|
||||
#define HUB_FEATURE_C_PORT_ENABLE 17
|
||||
#define HUB_FEATURE_C_PORT_SUSPEND 18
|
||||
#define HUB_FEATURE_C_PORT_OVER_CURRENT 19
|
||||
#define HUB_FEATURE_C_PORT_RESET 20
|
||||
#define HUB_FEATURE_PORT_TEST 21
|
||||
#define HUB_FEATURE_PORT_INDICATOR 22
|
||||
|
||||
// Additional Error Codes
|
||||
#define HUB_ERROR_PORT_HAS_BEEN_RESET 0xb1
|
||||
|
||||
// Hub Port Status Bitmasks
|
||||
#define USB_HUB_PORT_STATUS_PORT_CONNECTION 0x0001
|
||||
#define USB_HUB_PORT_STATUS_PORT_ENABLE 0x0002
|
||||
#define USB_HUB_PORT_STATUS_PORT_SUSPEND 0x0004
|
||||
#define USB_HUB_PORT_STATUS_PORT_OVER_CURRENT 0x0008
|
||||
#define USB_HUB_PORT_STATUS_PORT_RESET 0x0010
|
||||
#define USB_HUB_PORT_STATUS_PORT_POWER 0x0100
|
||||
#define USB_HUB_PORT_STATUS_PORT_LOW_SPEED 0x0200
|
||||
#define USB_HUB_PORT_STATUS_PORT_HIGH_SPEED 0x0400
|
||||
#define USB_HUB_PORT_STATUS_PORT_TEST 0x0800
|
||||
#define USB_HUB_PORT_STATUS_PORT_INDICATOR 0x1000
|
||||
|
||||
// Bit mask to check for DISABLED state in HubEvent::bmStatus field
|
||||
#define USB_HUB_PORT_STATE_CHECK_DISABLED (USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_ENABLE | USB_HUB_PORT_STATUS_PORT_CONNECTION | USB_HUB_PORT_STATUS_PORT_SUSPEND)
|
||||
|
||||
// Hub Port States
|
||||
#define USB_HUB_PORT_STATE_DISABLED (USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_CONNECTION)
|
||||
|
||||
// Hub Port Events
|
||||
#define USB_HUB_PORT_EVENT_CONNECT (((0UL | USB_HUB_PORT_STATUS_PORT_CONNECTION) << 16) | USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_CONNECTION)
|
||||
#define USB_HUB_PORT_EVENT_DISCONNECT (((0UL | USB_HUB_PORT_STATUS_PORT_CONNECTION) << 16) | USB_HUB_PORT_STATUS_PORT_POWER)
|
||||
#define USB_HUB_PORT_EVENT_RESET_COMPLETE (((0UL | USB_HUB_PORT_STATUS_PORT_RESET) << 16) | USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_ENABLE | USB_HUB_PORT_STATUS_PORT_CONNECTION)
|
||||
|
||||
#define USB_HUB_PORT_EVENT_LS_CONNECT (((0UL | USB_HUB_PORT_STATUS_PORT_CONNECTION) << 16) | USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_CONNECTION | USB_HUB_PORT_STATUS_PORT_LOW_SPEED)
|
||||
#define USB_HUB_PORT_EVENT_LS_RESET_COMPLETE (((0UL | USB_HUB_PORT_STATUS_PORT_RESET) << 16) | USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_ENABLE | USB_HUB_PORT_STATUS_PORT_CONNECTION | USB_HUB_PORT_STATUS_PORT_LOW_SPEED)
|
||||
#define USB_HUB_PORT_EVENT_LS_PORT_ENABLED (((0UL | USB_HUB_PORT_STATUS_PORT_CONNECTION | USB_HUB_PORT_STATUS_PORT_ENABLE) << 16) | USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_ENABLE | USB_HUB_PORT_STATUS_PORT_CONNECTION | USB_HUB_PORT_STATUS_PORT_LOW_SPEED)
|
||||
|
||||
typedef struct {
|
||||
uint8_t bDescLength; // descriptor length
|
||||
uint8_t bDescriptorType; // descriptor type
|
||||
uint8_t bNbrPorts; // number of ports a hub equiped with
|
||||
|
||||
struct {
|
||||
uint16_t LogPwrSwitchMode : 2;
|
||||
uint16_t CompoundDevice : 1;
|
||||
uint16_t OverCurrentProtectMode : 2;
|
||||
uint16_t TTThinkTime : 2;
|
||||
uint16_t PortIndicatorsSupported : 1;
|
||||
uint16_t Reserved : 8;
|
||||
} __attribute__((packed));
|
||||
|
||||
uint8_t bPwrOn2PwrGood;
|
||||
uint8_t bHubContrCurrent;
|
||||
} __attribute__((packed)) usb_hub_descriptor_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint16_t bmStatus; // port status bits
|
||||
uint16_t bmChange; // port status change bits
|
||||
} __attribute__((packed));
|
||||
uint32_t bmEvent;
|
||||
uint8_t evtBuff[4];
|
||||
} __attribute__((packed));
|
||||
}__attribute__((packed)) hub_event_t;
|
||||
|
||||
// interface to usb core
|
||||
extern const usb_device_class_config_t usb_hub_class;
|
||||
|
||||
#endif // HUB_H
|
||||
219
usb/max3421e.c
Normal file
219
usb/max3421e.c
Normal file
@@ -0,0 +1,219 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "max3421e.h"
|
||||
#include "timer.h"
|
||||
#include "spi.h"
|
||||
|
||||
static void hexdump(void *data, int size) {
|
||||
int i,n = 0, b2c;
|
||||
char *ptr = data;
|
||||
|
||||
if(!size) return;
|
||||
|
||||
while(size>0) {
|
||||
iprintf("%04x: ", n);
|
||||
|
||||
b2c = (size>16)?16:size;
|
||||
|
||||
for(i=0;i<b2c;i++)
|
||||
iprintf("%02x ", 0xff&ptr[i]);
|
||||
|
||||
iprintf(" ");
|
||||
|
||||
for(i=0;i<(16-b2c);i++)
|
||||
iprintf(" ");
|
||||
|
||||
for(i=0;i<b2c;i++)
|
||||
iprintf("%c", isprint(ptr[i])?ptr[i]:'.');
|
||||
|
||||
iprintf("\n");
|
||||
|
||||
ptr += b2c;
|
||||
size -= b2c;
|
||||
n += b2c;
|
||||
}
|
||||
}
|
||||
void max3421e_write_u08(uint8_t reg, uint8_t data) {
|
||||
// iprintf("write %x %x\n", reg, data);
|
||||
|
||||
spi_start(0);
|
||||
spi_xmit(reg | MAX3421E_WRITE);
|
||||
spi_xmit(data);
|
||||
spi_end();
|
||||
}
|
||||
|
||||
uint8_t max3421e_read_u08(uint8_t reg) {
|
||||
spi_start(0);
|
||||
spi_xmit(reg);
|
||||
uint8_t ret = spi_xmit(0);
|
||||
spi_end();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t *max3421e_write(uint8_t reg, uint8_t n, uint8_t* data) {
|
||||
// hexdump(data, n);
|
||||
|
||||
spi_start(0);
|
||||
spi_xmit(reg | MAX3421E_WRITE);
|
||||
while(n--) spi_xmit(*data++);
|
||||
spi_end();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
uint8_t *max3421e_read(uint8_t reg, uint8_t n, uint8_t* data) {
|
||||
spi_start(0);
|
||||
spi_xmit(reg);
|
||||
while(n--) *data++ = spi_xmit(0);
|
||||
spi_end();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static uint8_t vbusState = MAX3421E_STATE_SE0;
|
||||
|
||||
uint16_t max3421e_reset() {
|
||||
uint16_t i = 0;
|
||||
|
||||
/* reset chip */
|
||||
max3421e_write_u08( MAX3421E_USBCTL, MAX3421E_CHIPRES );
|
||||
max3421e_write_u08( MAX3421E_USBCTL, 0 );
|
||||
|
||||
/* wait for pll to synchronize */
|
||||
while( ++i ) {
|
||||
if(( max3421e_read_u08( MAX3421E_USBIRQ ) & MAX3421E_OSCOKIRQ )) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void max3421e_busprobe() {
|
||||
iprintf("busprobe()\n");
|
||||
|
||||
uint8_t bus_sample = max3421e_read_u08( MAX3421E_HRSL ); // Get J,K status
|
||||
bus_sample &= ( MAX3421E_JSTATUS | MAX3421E_KSTATUS ); // zero the rest of the byte
|
||||
switch( bus_sample ) { // start full-speed or low-speed host
|
||||
case MAX3421E_JSTATUS:
|
||||
if( !(max3421e_read_u08( MAX3421E_MODE ) & MAX3421E_LOWSPEED) ) {
|
||||
max3421e_write_u08( MAX3421E_MODE, MAX3421E_MODE_FS_HOST );
|
||||
vbusState = MAX3421E_STATE_FSHOST;
|
||||
} else {
|
||||
max3421e_write_u08( MAX3421E_MODE, MAX3421E_MODE_LS_HOST);
|
||||
vbusState = MAX3421E_STATE_LSHOST;
|
||||
}
|
||||
break;
|
||||
|
||||
case MAX3421E_KSTATUS:
|
||||
if( !(max3421e_read_u08( MAX3421E_MODE ) & MAX3421E_LOWSPEED) ) {
|
||||
max3421e_write_u08( MAX3421E_MODE, MAX3421E_MODE_LS_HOST );
|
||||
vbusState = MAX3421E_STATE_LSHOST;
|
||||
} else {
|
||||
max3421e_write_u08( MAX3421E_MODE, MAX3421E_MODE_FS_HOST );
|
||||
vbusState = MAX3421E_STATE_FSHOST;
|
||||
}
|
||||
break;
|
||||
|
||||
case MAX3421E_SE1: // illegal state
|
||||
vbusState = MAX3421E_STATE_SE1;
|
||||
break;
|
||||
|
||||
case MAX3421E_SE0: // disconnected state
|
||||
max3421e_write_u08( MAX3421E_MODE, MAX3421E_DPPULLDN | MAX3421E_DMPULLDN | MAX3421E_HOST | MAX3421E_SEPIRQ);
|
||||
vbusState = MAX3421E_STATE_SE0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void max3421e_init() {
|
||||
iprintf("max3421e_init()\n");
|
||||
|
||||
timer_init();
|
||||
spi_init();
|
||||
|
||||
// switch to full duplex mode
|
||||
max3421e_write_u08(MAX3421E_PINCTL, MAX3421E_FDUPSPI | MAX3421E_INTLEVEL);
|
||||
|
||||
// read and output version
|
||||
iprintf("Chip revision: %x\n", max3421e_read_u08(MAX3421E_REVISION));
|
||||
|
||||
if( max3421e_reset() == 0 ) {
|
||||
iprintf("pll init failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// enable pulldowns, set host mode
|
||||
max3421e_write_u08( MAX3421E_MODE, MAX3421E_DPPULLDN | MAX3421E_DMPULLDN | MAX3421E_HOST );
|
||||
|
||||
// enable interrupts
|
||||
// max3421e_write_u08( MAX3421E_HIEN, MAX3421E_CONDETIE| MAX3421E_FRAMEIE );
|
||||
max3421e_write_u08( MAX3421E_HIEN, MAX3421E_CONDETIE );
|
||||
|
||||
/* check if device is connected */
|
||||
|
||||
// sample USB bus
|
||||
max3421e_write_u08( MAX3421E_HCTL,MAX3421E_SAMPLEBUS );
|
||||
|
||||
// wait for sample operation to finish
|
||||
while(!(max3421e_read_u08( MAX3421E_HCTL ) & MAX3421E_SAMPLEBUS ));
|
||||
|
||||
// check if anything is connected
|
||||
max3421e_busprobe();
|
||||
|
||||
// clear connection detect interrupt
|
||||
max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_CONDETIRQ );
|
||||
|
||||
// enable interrupts
|
||||
max3421e_write_u08( MAX3421E_CPUCTL, MAX3421E_IE );
|
||||
return;
|
||||
}
|
||||
|
||||
#include "timer.h"
|
||||
|
||||
uint8_t max3421e_poll() {
|
||||
uint8_t hirq = max3421e_read_u08( MAX3421E_HIRQ );
|
||||
|
||||
#if 0
|
||||
static msec_t next = 0;
|
||||
if(timer_get_msec() > next) {
|
||||
iprintf("irq src=%x, bus state %x\n", hirq, vbusState);
|
||||
iprintf("host result %x\n", max3421e_read_u08( MAX3421E_HRSL));
|
||||
|
||||
next = timer_get_msec() + 10000;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( hirq & MAX3421E_CONDETIRQ ) {
|
||||
iprintf("=> CONDETIRQ\n");
|
||||
max3421e_busprobe();
|
||||
max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_CONDETIRQ );
|
||||
}
|
||||
|
||||
if( hirq & MAX3421E_BUSEVENTIRQ) {
|
||||
iprintf("=> BUSEVENTIRQ\n");
|
||||
max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_BUSEVENTIRQ );
|
||||
}
|
||||
|
||||
if( hirq & MAX3421E_SNDBAVIRQ) {
|
||||
// iprintf("=> MAX3421E_SNDBAVIRQ\n");
|
||||
max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_SNDBAVIRQ);
|
||||
}
|
||||
|
||||
if( hirq & MAX3421E_FRAMEIRQ) {
|
||||
// iprintf("=> MAX3421E_FRAMEIRQ\n");
|
||||
max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_FRAMEIRQ);
|
||||
}
|
||||
|
||||
#if 0
|
||||
int i;
|
||||
for(i=0;i<8;i++) {
|
||||
if(hirq & 1<<i) {
|
||||
iprintf("ack irq %d\n", 1<<i);
|
||||
// max3421e_write_u08( MAX3421E_HIRQ, i );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return vbusState;
|
||||
}
|
||||
|
||||
216
usb/max3421e.h
Normal file
216
usb/max3421e.h
Normal file
@@ -0,0 +1,216 @@
|
||||
|
||||
#ifndef MAX3421E_H
|
||||
#define MAX3421E_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#define MAX3421E_STATE_SE0 0
|
||||
#define MAX3421E_STATE_SE1 1
|
||||
#define MAX3421E_STATE_FSHOST 2
|
||||
#define MAX3421E_STATE_LSHOST 3
|
||||
|
||||
#define MAX3421E_WRITE 0x02
|
||||
|
||||
/* MAX3421E command byte format: rrrrr0wa where 'r' is register number */
|
||||
//
|
||||
// MAX3421E Registers in HOST mode.
|
||||
//
|
||||
#define MAX3421E_RCVFIFO 0x08 //1<<3
|
||||
#define MAX3421E_SNDFIFO 0x10 //2<<3
|
||||
#define MAX3421E_SUDFIFO 0x20 //4<<3
|
||||
#define MAX3421E_RCVBC 0x30 //6<<3
|
||||
#define MAX3421E_SNDBC 0x38 //7<<3
|
||||
|
||||
#define MAX3421E_USBIRQ 0x68 //13<<3
|
||||
/* USBIRQ Bits */
|
||||
#define MAX3421E_VBUSIRQ 0x40 //b6
|
||||
#define MAX3421E_NOVBUSIRQ 0x20 //b5
|
||||
#define MAX3421E_OSCOKIRQ 0x01 //b0
|
||||
|
||||
#define MAX3421E_USBIEN 0x70 //14<<3
|
||||
/* USBIEN Bits */
|
||||
#define bmVBUSIE 0x40 //b6
|
||||
#define bmNOVBUSIE 0x20 //b5
|
||||
#define bmOSCOKIE 0x01 //b0
|
||||
|
||||
#define MAX3421E_USBCTL 0x78 //15<<3
|
||||
/* USBCTL Bits */
|
||||
#define MAX3421E_CHIPRES 0x20 //b5
|
||||
#define MAX3421E_PWRDOWN 0x10 //b4
|
||||
|
||||
#define MAX3421E_CPUCTL 0x80 //16<<3
|
||||
/* CPUCTL Bits */
|
||||
#define MAX3421E_PUSLEWID1 0x80 //b7
|
||||
#define MAX3421E_PULSEWID0 0x40 //b6
|
||||
#define MAX3421E_IE 0x01 //b0
|
||||
|
||||
#define MAX3421E_PINCTL 0x88 //17<<3
|
||||
/* PINCTL Bits */
|
||||
#define MAX3421E_FDUPSPI 0x10 //b4
|
||||
#define MAX3421E_INTLEVEL 0x08 //b3
|
||||
#define MAX3421E_POSINT 0x04 //b2
|
||||
#define MAX3421E_GPXB 0x02 //b1
|
||||
#define MAX3421E_GPXA 0x01 //b0
|
||||
// GPX pin selections
|
||||
#define MAX3421E_GPX_OPERATE 0x00
|
||||
#define MAX3421E_GPX_VBDET 0x01
|
||||
#define MAX3421E_GPX_BUSACT 0x02
|
||||
#define MAX3421E_GPX_SOF 0x03
|
||||
|
||||
#define MAX3421E_REVISION 0x90 //18<<3
|
||||
|
||||
#define MAX3421E_IOPINS1 0xa0 //20<<3
|
||||
|
||||
/* IOPINS1 Bits */
|
||||
#define bmGPOUT0 0x01
|
||||
#define bmGPOUT1 0x02
|
||||
#define bmGPOUT2 0x04
|
||||
#define bmGPOUT3 0x08
|
||||
#define bmGPIN0 0x10
|
||||
#define bmGPIN1 0x20
|
||||
#define bmGPIN2 0x40
|
||||
#define bmGPIN3 0x80
|
||||
|
||||
#define MAX3421E_IOPINS2 0xa8 //21<<3
|
||||
/* IOPINS2 Bits */
|
||||
#define bmGPOUT4 0x01
|
||||
#define bmGPOUT5 0x02
|
||||
#define bmGPOUT6 0x04
|
||||
#define bmGPOUT7 0x08
|
||||
#define bmGPIN4 0x10
|
||||
#define bmGPIN5 0x20
|
||||
#define bmGPIN6 0x40
|
||||
#define bmGPIN7 0x80
|
||||
|
||||
#define MAX3421E_GPINIRQ 0xb0 //22<<3
|
||||
/* GPINIRQ Bits */
|
||||
#define bmGPINIRQ0 0x01
|
||||
#define bmGPINIRQ1 0x02
|
||||
#define bmGPINIRQ2 0x04
|
||||
#define bmGPINIRQ3 0x08
|
||||
#define bmGPINIRQ4 0x10
|
||||
#define bmGPINIRQ5 0x20
|
||||
#define bmGPINIRQ6 0x40
|
||||
#define bmGPINIRQ7 0x80
|
||||
|
||||
#define MAX3421E_GPINIEN 0xb8 //23<<3
|
||||
/* GPINIEN Bits */
|
||||
#define bmGPINIEN0 0x01
|
||||
#define bmGPINIEN1 0x02
|
||||
#define bmGPINIEN2 0x04
|
||||
#define bmGPINIEN3 0x08
|
||||
#define bmGPINIEN4 0x10
|
||||
#define bmGPINIEN5 0x20
|
||||
#define bmGPINIEN6 0x40
|
||||
#define bmGPINIEN7 0x80
|
||||
|
||||
#define MAX3421E_GPINPOL 0xc0 //24<<3
|
||||
/* GPINPOL Bits */
|
||||
#define bmGPINPOL0 0x01
|
||||
#define bmGPINPOL1 0x02
|
||||
#define bmGPINPOL2 0x04
|
||||
#define bmGPINPOL3 0x08
|
||||
#define bmGPINPOL4 0x10
|
||||
#define bmGPINPOL5 0x20
|
||||
#define bmGPINPOL6 0x40
|
||||
#define bmGPINPOL7 0x80
|
||||
|
||||
#define MAX3421E_HIRQ 0xc8 //25<<3
|
||||
/* HIRQ Bits */
|
||||
#define MAX3421E_BUSEVENTIRQ 0x01 // indicates BUS reset Done or BUS resume
|
||||
#define MAX3421E_RWUIRQ 0x02
|
||||
#define MAX3421E_RCVDAVIRQ 0x04
|
||||
#define MAX3421E_SNDBAVIRQ 0x08
|
||||
#define MAX3421E_SUSDNIRQ 0x10
|
||||
#define MAX3421E_CONDETIRQ 0x20
|
||||
#define MAX3421E_FRAMEIRQ 0x40
|
||||
#define MAX3421E_HXFRDNIRQ 0x80
|
||||
|
||||
#define MAX3421E_HIEN 0xd0 //26<<3
|
||||
|
||||
/* HIEN Bits */
|
||||
#define MAX3421E_BUSEVENTIE 0x01
|
||||
#define MAX3421E_RWUIE 0x02
|
||||
#define MAX3421E_RCVDAVIE 0x04
|
||||
#define MAX3421E_SNDBAVIE 0x08
|
||||
#define MAX3421E_SUSDNIE 0x10
|
||||
#define MAX3421E_CONDETIE 0x20
|
||||
#define MAX3421E_FRAMEIE 0x40
|
||||
#define MAX3421E_HXFRDNIE 0x80
|
||||
|
||||
#define MAX3421E_MODE 0xd8 //27<<3
|
||||
|
||||
/* MODE Bits */
|
||||
#define MAX3421E_HOST 0x01
|
||||
#define MAX3421E_LOWSPEED 0x02
|
||||
#define MAX3421E_HUBPRE 0x04
|
||||
#define MAX3421E_SOFKAENAB 0x08
|
||||
#define MAX3421E_SEPIRQ 0x10
|
||||
#define MAX3421E_DELAYISO 0x20
|
||||
#define MAX3421E_DMPULLDN 0x40
|
||||
#define MAX3421E_DPPULLDN 0x80
|
||||
|
||||
#define MAX3421E_PERADDR 0xe0 //28<<3
|
||||
|
||||
#define MAX3421E_HCTL 0xe8 //29<<3
|
||||
/* HCTL Bits */
|
||||
#define MAX3421E_BUSRST 0x01
|
||||
#define MAX3421E_FRMRST 0x02
|
||||
#define MAX3421E_SAMPLEBUS 0x04
|
||||
#define MAX3421E_SIGRSM 0x08
|
||||
#define MAX3421E_RCVTOG0 0x10
|
||||
#define MAX3421E_RCVTOG1 0x20
|
||||
#define MAX3421E_SNDTOG0 0x40
|
||||
#define MAX3421E_SNDTOG1 0x80
|
||||
|
||||
#define MAX3421E_HXFR 0xf0 //30<<3
|
||||
/* Host transfer token values for writing the HXFR MAX3421E_egister (R30) */
|
||||
/* OR this bit field with the endpoint number in bits 3:0 */
|
||||
#define tokSETUP 0x10 // HS=0, ISO=0, OUTNIN=0, SETUP=1
|
||||
#define tokIN 0x00 // HS=0, ISO=0, OUTNIN=0, SETUP=0
|
||||
#define tokOUT 0x20 // HS=0, ISO=0, OUTNIN=1, SETUP=0
|
||||
#define tokINHS 0x80 // HS=1, ISO=0, OUTNIN=0, SETUP=0
|
||||
#define tokOUTHS 0xA0 // HS=1, ISO=0, OUTNIN=1, SETUP=0
|
||||
#define tokISOIN 0x40 // HS=0, ISO=1, OUTNIN=0, SETUP=0
|
||||
#define tokISOOUT 0x60 // HS=0, ISO=1, OUTNIN=1, SETUP=0
|
||||
|
||||
#define MAX3421E_HRSL 0xf8 //31<<3
|
||||
|
||||
/* HRSL Bits */
|
||||
#define MAX3421E_RCVTOGRD 0x10
|
||||
#define MAX3421E_SNDTOGRD 0x20
|
||||
#define MAX3421E_KSTATUS 0x40
|
||||
#define MAX3421E_JSTATUS 0x80
|
||||
#define MAX3421E_SE0 0x00 //SE0 - disconnect state
|
||||
#define MAX3421E_SE1 0xc0 //SE1 - illegal state
|
||||
|
||||
/* Host error MAX3421E_esult codes, the 4 LSB's in the HRSL register */
|
||||
#define hrSUCCESS 0x00
|
||||
#define hrBUSY 0x01
|
||||
#define hrBADREQ 0x02
|
||||
#define hrUNDEF 0x03
|
||||
#define hrNAK 0x04
|
||||
#define hrSTALL 0x05
|
||||
#define hrTOGERR 0x06
|
||||
#define hrWRONGPID 0x07
|
||||
#define hrBADBC 0x08
|
||||
#define hrPIDERR 0x09
|
||||
#define hrPKTERR 0x0A
|
||||
#define hrCRCERR 0x0B
|
||||
#define hrKERR 0x0C
|
||||
#define hrJERR 0x0D
|
||||
#define hrTIMEOUT 0x0E
|
||||
#define hrBABBLE 0x0F
|
||||
|
||||
#define MAX3421E_MODE_FS_HOST (MAX3421E_DPPULLDN|MAX3421E_DMPULLDN|MAX3421E_HOST|MAX3421E_SOFKAENAB)
|
||||
#define MAX3421E_MODE_LS_HOST (MAX3421E_DPPULLDN|MAX3421E_DMPULLDN|MAX3421E_HOST|MAX3421E_LOWSPEED|MAX3421E_SOFKAENAB)
|
||||
|
||||
// interface used by usb.c
|
||||
void max3421e_init();
|
||||
uint8_t max3421e_poll();
|
||||
void max3421e_write_u08(uint8_t reg, uint8_t data);
|
||||
uint8_t max3421e_read_u08(uint8_t reg);
|
||||
uint8_t *max3421e_write(uint8_t reg, uint8_t n, uint8_t* data);
|
||||
uint8_t *max3421e_read(uint8_t reg, uint8_t n, uint8_t* data);
|
||||
|
||||
#endif //_max3421e_h_
|
||||
14
usb/spi.h
Normal file
14
usb/spi.h
Normal file
@@ -0,0 +1,14 @@
|
||||
// interface between USB spi and minimig spi
|
||||
|
||||
#ifndef SPI_H
|
||||
#define SPI_H
|
||||
|
||||
#include "AT91SAM7S256.h"
|
||||
#include "hardware.h"
|
||||
|
||||
#define spi_init()
|
||||
#define spi_start(a) { *AT91C_PIOA_CODR = USB_SEL; }
|
||||
#define spi_end() { SPI_Wait4XferEnd(); *AT91C_PIOA_SODR = USB_SEL; }
|
||||
#define spi_xmit(a) SPI(a)
|
||||
|
||||
#endif // SPI_H
|
||||
17
usb/timer.c
Normal file
17
usb/timer.c
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "timer.h"
|
||||
#include "AT91SAM7S256.h"
|
||||
|
||||
void timer_init() {
|
||||
// reprogram the realtime timer to run at 1Khz
|
||||
AT91C_BASE_RTTC->RTTC_RTMR = 0x8000 / 1000;
|
||||
}
|
||||
|
||||
msec_t timer_get_msec() {
|
||||
return AT91C_BASE_RTTC->RTTC_RTVR;
|
||||
}
|
||||
|
||||
void timer_delay_msec(msec_t t) {
|
||||
msec_t now = AT91C_BASE_RTTC->RTTC_RTVR;
|
||||
|
||||
while(AT91C_BASE_RTTC->RTTC_RTVR - now < t);
|
||||
}
|
||||
13
usb/timer.h
Normal file
13
usb/timer.h
Normal file
@@ -0,0 +1,13 @@
|
||||
// interface between USB timer and minimig timer
|
||||
|
||||
#ifndef TIMER_H
|
||||
#define TIMER_H
|
||||
|
||||
#include <inttypes.h>
|
||||
typedef uint32_t msec_t;
|
||||
|
||||
void timer_init();
|
||||
msec_t timer_get_msec();
|
||||
void timer_delay_msec(msec_t t);
|
||||
|
||||
#endif // TIMER_H
|
||||
590
usb/usb.c
Normal file
590
usb/usb.c
Normal file
@@ -0,0 +1,590 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "timer.h"
|
||||
#include "max3421e.h"
|
||||
#include "usb.h"
|
||||
|
||||
static uint8_t usb_task_state;
|
||||
static uint8_t bmHubPre;
|
||||
|
||||
static usb_device_t dev[USB_NUMDEVICES];
|
||||
|
||||
void usb_reset_state() {
|
||||
puts(__FUNCTION__);
|
||||
bmHubPre = 0;
|
||||
}
|
||||
|
||||
usb_device_t *usb_get_devices() {
|
||||
return dev;
|
||||
}
|
||||
|
||||
void usb_init() {
|
||||
puts(__FUNCTION__);
|
||||
|
||||
max3421e_init(); // init underlaying hardware layer
|
||||
|
||||
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
|
||||
|
||||
uint8_t i;
|
||||
for(i=0;i<USB_NUMDEVICES;i++)
|
||||
dev[i].bAddress = 0;
|
||||
|
||||
usb_reset_state();
|
||||
}
|
||||
|
||||
uint8_t usb_set_address(usb_device_t *dev, ep_t *ep,
|
||||
uint16_t *nak_limit) {
|
||||
// iprintf(" %s(addr=%x, ep=%d)\n", __FUNCTION__, addr, ep);
|
||||
*nak_limit = (1UL << ( ( ep->bmNakPower > USB_NAK_MAX_POWER ) ?
|
||||
USB_NAK_MAX_POWER : ep->bmNakPower) ) - 1;
|
||||
|
||||
/*
|
||||
iprintf("\nAddress: %x\n", addr);
|
||||
iprintf(" EP: %d\n", ep);
|
||||
iprintf(" NAK Power: %d\n",(*ppep)->bmNakPower);
|
||||
iprintf(" NAK Limit: %d\n", nak_limit);
|
||||
*/
|
||||
|
||||
max3421e_write_u08( MAX3421E_PERADDR, dev->bAddress); // set peripheral address
|
||||
|
||||
uint8_t mode = max3421e_read_u08( MAX3421E_MODE );
|
||||
|
||||
// Set bmLOWSPEED and bmHUBPRE in case of low-speed device,
|
||||
// reset them otherwise
|
||||
max3421e_write_u08( MAX3421E_MODE,
|
||||
(dev->lowspeed) ? mode | MAX3421E_LOWSPEED | bmHubPre :
|
||||
mode & ~(MAX3421E_HUBPRE | MAX3421E_LOWSPEED));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* dispatch usb packet. Assumes peripheral address is set and relevant */
|
||||
/* buffer is loaded/empty */
|
||||
/* If NAK, tries to re-send up to nak_limit times */
|
||||
/* If nak_limit == 0, do not count NAKs, exit after timeout */
|
||||
/* If bus timeout, re-sends up to USB_RETRY_LIMIT times */
|
||||
/* return codes 0x00-0x0f are HRSLT (0x00 being success), 0xff means timeout */
|
||||
uint8_t usb_dispatchPkt( uint8_t token, uint8_t ep, uint16_t nak_limit ) {
|
||||
// iprintf(" %s(token=%x, ep=%d, nak_limit=%d)\n",
|
||||
// __FUNCTION__, token, ep, nak_limit);
|
||||
unsigned long timeout = timer_get_msec() + USB_XFER_TIMEOUT;
|
||||
uint8_t tmpdata;
|
||||
uint8_t rcode = 0x00;
|
||||
uint8_t retry_count = 0;
|
||||
uint16_t nak_count = 0;
|
||||
|
||||
while( timeout > timer_get_msec() ) {
|
||||
max3421e_write_u08( MAX3421E_HXFR, ( token|ep )); //launch the transfer
|
||||
rcode = USB_ERROR_TRANSFER_TIMEOUT;
|
||||
|
||||
// wait for transfer completion
|
||||
while( timer_get_msec() < timeout ) {
|
||||
tmpdata = max3421e_read_u08( MAX3421E_HIRQ );
|
||||
|
||||
if( tmpdata & MAX3421E_HXFRDNIRQ ) {
|
||||
//clear the interrupt
|
||||
max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_HXFRDNIRQ );
|
||||
rcode = 0x00;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( rcode != 0x00 ) //exit if timeout
|
||||
return( rcode );
|
||||
|
||||
//analyze transfer result
|
||||
rcode = ( max3421e_read_u08( MAX3421E_HRSL ) & 0x0f );
|
||||
|
||||
switch( rcode ) {
|
||||
|
||||
case hrNAK:
|
||||
nak_count++;
|
||||
if( nak_limit && ( nak_count == nak_limit ))
|
||||
return( rcode );
|
||||
break;
|
||||
|
||||
case hrTIMEOUT:
|
||||
retry_count++;
|
||||
if( retry_count == USB_RETRY_LIMIT )
|
||||
return( rcode );
|
||||
break;
|
||||
|
||||
default:
|
||||
return( rcode );
|
||||
}
|
||||
}
|
||||
|
||||
return( rcode );
|
||||
}
|
||||
|
||||
uint8_t usb_InTransfer(ep_t *pep, uint16_t nak_limit,
|
||||
uint16_t *nbytesptr, uint8_t* data) {
|
||||
uint8_t rcode = 0;
|
||||
uint8_t pktsize;
|
||||
|
||||
uint16_t nbytes = *nbytesptr;
|
||||
uint8_t maxpktsize = pep->maxPktSize;
|
||||
|
||||
*nbytesptr = 0;
|
||||
// set toggle value
|
||||
max3421e_write_u08( MAX3421E_HCTL,
|
||||
(pep->bmRcvToggle) ? MAX3421E_RCVTOG1 : MAX3421E_RCVTOG0 );
|
||||
|
||||
// use a 'return' to exit this loop
|
||||
while( 1 ) {
|
||||
//IN packet to EP-'endpoint'. Function takes care of NAKS.
|
||||
rcode = usb_dispatchPkt( tokIN, pep->epAddr, nak_limit );
|
||||
|
||||
//should be 0, indicating ACK. Else return error code.
|
||||
if( rcode )
|
||||
return( rcode );
|
||||
|
||||
/* check for RCVDAVIRQ and generate error if not present */
|
||||
/* the only case when absense of RCVDAVIRQ makes sense is when */
|
||||
/* toggle error occured. Need to add handling for that */
|
||||
if(( max3421e_read_u08( MAX3421E_HIRQ ) & MAX3421E_RCVDAVIRQ ) == 0 )
|
||||
return ( 0xf0 ); //receive error
|
||||
|
||||
pktsize = max3421e_read_u08( MAX3421E_RCVBC ); // number of received bytes
|
||||
|
||||
//XXX assert(pktsize <= nbytes);
|
||||
|
||||
int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr);
|
||||
|
||||
if (mem_left < 0)
|
||||
mem_left = 0;
|
||||
|
||||
// iprintf("rx %d of %d\n", pktsize, mem_left);
|
||||
data = max3421e_read(MAX3421E_RCVFIFO,
|
||||
((pktsize > mem_left) ? mem_left : pktsize), data );
|
||||
|
||||
// Clear the IRQ & free the buffer
|
||||
max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_RCVDAVIRQ );
|
||||
*nbytesptr += pktsize;
|
||||
// add this packet's byte count to total transfer length
|
||||
/* The transfer is complete under two conditions: */
|
||||
/* 1. The device sent a short packet (L.T. maxPacketSize) */
|
||||
/* 2. 'nbytes' have been transferred. */
|
||||
|
||||
// have we transferred 'nbytes' bytes?
|
||||
if (( pktsize < maxpktsize ) || (*nbytesptr >= nbytes )) {
|
||||
// Save toggle value
|
||||
pep->bmRcvToggle = (( max3421e_read_u08( MAX3421E_HRSL ) &
|
||||
MAX3421E_RCVTOGRD )) ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets */
|
||||
/* if necessary. Transfers 'nbytes' bytes. Keep sending INs and writes data to memory area */
|
||||
/* pointed by 'data' */
|
||||
/* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error, */
|
||||
/* fe USB xfer timeout */
|
||||
uint8_t usb_in_transfer( usb_device_t *dev, ep_t *ep, uint16_t *nbytesptr, uint8_t* data) {
|
||||
uint16_t nak_limit = 0;
|
||||
|
||||
uint8_t rcode = usb_set_address(dev, ep, &nak_limit);
|
||||
if (rcode)
|
||||
return rcode;
|
||||
|
||||
return usb_InTransfer(ep, nak_limit, nbytesptr, data);
|
||||
}
|
||||
|
||||
uint8_t usb_OutTransfer(ep_t *pep, uint16_t nak_limit,
|
||||
uint16_t nbytes, uint8_t *data) {
|
||||
iprintf("%s(%d)\n", __FUNCTION__, nbytes);
|
||||
|
||||
uint8_t rcode = 0, retry_count;
|
||||
uint16_t bytes_tosend, nak_count;
|
||||
uint16_t bytes_left = nbytes;
|
||||
|
||||
uint8_t maxpktsize = pep->maxPktSize;
|
||||
|
||||
if (maxpktsize < 1 || maxpktsize > 64)
|
||||
return USB_ERROR_INVALID_MAX_PKT_SIZE;
|
||||
|
||||
unsigned long timeout = timer_get_msec() + USB_XFER_TIMEOUT;
|
||||
|
||||
//set toggle value
|
||||
max3421e_write_u08(MAX3421E_HCTL,
|
||||
(pep->bmSndToggle) ? MAX3421E_SNDTOG1 : MAX3421E_SNDTOG0 );
|
||||
|
||||
while( bytes_left ) {
|
||||
retry_count = 0;
|
||||
nak_count = 0;
|
||||
bytes_tosend = ( bytes_left >= maxpktsize ) ? maxpktsize : bytes_left;
|
||||
|
||||
//filling output FIFO
|
||||
max3421e_write( MAX3421E_SNDFIFO, bytes_tosend, data );
|
||||
|
||||
//set number of bytes
|
||||
max3421e_write_u08( MAX3421E_SNDBC, bytes_tosend );
|
||||
|
||||
// dispatch packet
|
||||
max3421e_write_u08( MAX3421E_HXFR, ( tokOUT | pep->epAddr ));
|
||||
|
||||
//wait for the completion IRQ
|
||||
while(!(max3421e_read_u08( MAX3421E_HIRQ ) & MAX3421E_HXFRDNIRQ ));
|
||||
max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_HXFRDNIRQ ); //clear IRQ
|
||||
rcode = max3421e_read_u08( MAX3421E_HRSL ) & 0x0f;
|
||||
|
||||
while( rcode && ( timeout > timer_get_msec())) {
|
||||
switch( rcode ) {
|
||||
case hrNAK:
|
||||
nak_count ++;
|
||||
if( nak_limit && ( nak_count == nak_limit ))
|
||||
return( rcode );
|
||||
break;
|
||||
case hrTIMEOUT:
|
||||
retry_count ++;
|
||||
if( retry_count == USB_RETRY_LIMIT )
|
||||
return( rcode );
|
||||
break;
|
||||
default:
|
||||
return( rcode );
|
||||
}
|
||||
|
||||
/* process NAK according to Host out NAK bug */
|
||||
max3421e_write_u08( MAX3421E_SNDBC, 0 );
|
||||
max3421e_write_u08( MAX3421E_SNDFIFO, *data );
|
||||
max3421e_write_u08( MAX3421E_SNDBC, bytes_tosend );
|
||||
|
||||
// dispatch packet
|
||||
max3421e_write_u08( MAX3421E_HXFR, ( tokOUT | pep->epAddr ));
|
||||
|
||||
// wait for the completion IRQ
|
||||
while(!(max3421e_read_u08( MAX3421E_HIRQ ) & MAX3421E_HXFRDNIRQ ));
|
||||
max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_HXFRDNIRQ ); // clear IRQ
|
||||
rcode = ( max3421e_read_u08( MAX3421E_HRSL ) & 0x0f );
|
||||
}//while( rcode && ....
|
||||
bytes_left -= bytes_tosend;
|
||||
data += bytes_tosend;
|
||||
}//while( bytes_left...
|
||||
|
||||
//update toggle
|
||||
pep->bmSndToggle = ( max3421e_read_u08( MAX3421E_HRSL ) & MAX3421E_SNDTOGRD ) ? 1 : 0;
|
||||
return( rcode ); //should be 0 in all cases
|
||||
}
|
||||
|
||||
/* Control transfer. Sets address, endpoint, fills control packet */
|
||||
/* with necessary data, dispatches control packet, and initiates */
|
||||
/* bulk IN transfer, depending on request. Actual requests are defined */
|
||||
/* as inlines */
|
||||
/* return codes: */
|
||||
/* 00 = success */
|
||||
/* 01-0f = non-zero HRSLT */
|
||||
|
||||
uint8_t usb_ctrl_req(usb_device_t *dev, uint8_t bmReqType,
|
||||
uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
|
||||
uint16_t wInd, uint16_t total, uint16_t nbytes,
|
||||
uint8_t* dataptr, usb_parser_t *p) {
|
||||
iprintf("%s(addr=%x, len=%d, ptr=%p)\n", __FUNCTION__,
|
||||
dev->bAddress, nbytes, dataptr);
|
||||
bool direction = false; //request direction, IN or OUT
|
||||
uint8_t rcode;
|
||||
setup_pkt_t setup_pkt;
|
||||
uint16_t nak_limit;
|
||||
|
||||
rcode = usb_set_address(dev, &(dev->ep0), &nak_limit);
|
||||
if (rcode)
|
||||
return rcode;
|
||||
|
||||
direction = (( bmReqType & 0x80 ) > 0);
|
||||
|
||||
/* fill in setup packet */
|
||||
setup_pkt.ReqType_u.bmRequestType = bmReqType;
|
||||
setup_pkt.bRequest = bRequest;
|
||||
setup_pkt.wVal_u.wValueLo = wValLo;
|
||||
setup_pkt.wVal_u.wValueHi = wValHi;
|
||||
setup_pkt.wIndex = wInd;
|
||||
setup_pkt.wLength = total;
|
||||
|
||||
// transfer to setup packet FIFO
|
||||
max3421e_write(MAX3421E_SUDFIFO, sizeof(setup_pkt_t), (uint8_t*)&setup_pkt );
|
||||
|
||||
rcode = usb_dispatchPkt( tokSETUP, 0, nak_limit ); //dispatch packet
|
||||
if( rcode ) //return HRSLT if not zero
|
||||
return( rcode );
|
||||
|
||||
// data stage, if present
|
||||
if( dataptr != NULL ) {
|
||||
if( direction ) { //IN transfer
|
||||
uint16_t left = total;
|
||||
|
||||
dev->ep0.bmRcvToggle = 1; //bmRCVTOG1;
|
||||
|
||||
while (left) {
|
||||
// Bytes read into buffer
|
||||
uint16_t read = nbytes;
|
||||
//uint16_t read = (left<nbytes) ? left : nbytes;
|
||||
|
||||
rcode = usb_InTransfer( &(dev->ep0), nak_limit, &read, dataptr );
|
||||
|
||||
if (rcode)
|
||||
return rcode;
|
||||
|
||||
// Invoke callback function if inTransfer completed
|
||||
// successfuly and callback function pointer is specified
|
||||
if (!rcode && p)
|
||||
(*p)(read, dataptr, total - left);
|
||||
|
||||
left -= read;
|
||||
|
||||
if (read < nbytes)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
//OUT transfer
|
||||
dev->ep0.bmSndToggle = 1;
|
||||
rcode = usb_OutTransfer( &(dev->ep0), nak_limit, nbytes, dataptr );
|
||||
}
|
||||
|
||||
//return error
|
||||
if( rcode )
|
||||
return( rcode );
|
||||
}
|
||||
|
||||
// Status stage
|
||||
// GET if direction
|
||||
return usb_dispatchPkt( (direction) ? tokOUTHS : tokINHS, 0, nak_limit );
|
||||
}
|
||||
|
||||
// list of supported device classes
|
||||
static const usb_device_class_config_t *class_list[] = {
|
||||
&usb_hub_class,
|
||||
&usb_hid_class,
|
||||
NULL
|
||||
};
|
||||
|
||||
uint8_t usb_configure(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||
uint8_t rcode = 0;
|
||||
iprintf("%s(parent=%x port=%d lowspeed=%d)\n", __FUNCTION__, parent, port, lowspeed);
|
||||
|
||||
// find an empty device entry
|
||||
uint8_t i;
|
||||
for(i=0; i<USB_NUMDEVICES && dev[i].bAddress; i++);
|
||||
|
||||
if(i < USB_NUMDEVICES) {
|
||||
iprintf("using free entry at %d\n", i);
|
||||
|
||||
usb_device_t *d = dev+i;
|
||||
|
||||
// setup generic info
|
||||
d->bAddress = 0;
|
||||
d->parent = parent;
|
||||
d->lowspeed = lowspeed;
|
||||
d->port = port;
|
||||
d->class = NULL;
|
||||
|
||||
// setup endpoint 0
|
||||
d->ep0.epAddr = 0;
|
||||
d->ep0.maxPktSize = 8;
|
||||
d->ep0.epAttribs = 0;
|
||||
d->ep0.bmNakPower = USB_NAK_MAX_POWER;
|
||||
|
||||
// --- enumerate device ---
|
||||
|
||||
// Assign new address to the device
|
||||
// (address is simply the number of the free slot + 1)
|
||||
iprintf("Setting addr %x\n", i+1);
|
||||
rcode = usb_set_addr(d, i+1);
|
||||
if(rcode) {
|
||||
puts("failed to assign address");
|
||||
return rcode;
|
||||
}
|
||||
|
||||
// try to connect device to one of the supported classes
|
||||
uint8_t c;
|
||||
for(c=0;class_list[c];c++) {
|
||||
iprintf("trying to init class %d\n", c);
|
||||
rcode = class_list[c]->init(d);
|
||||
|
||||
if (!rcode) {
|
||||
d->class = class_list[c];
|
||||
|
||||
puts(" -> accepted :-)");
|
||||
// ok, device accepted by class
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
puts(" -> not accepted :-(");
|
||||
}
|
||||
} else
|
||||
iprintf("no more free entries\n");
|
||||
|
||||
iprintf("unsupported device\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usb_poll() {
|
||||
uint8_t rcode;
|
||||
uint8_t tmpdata;
|
||||
static msec_t delay = 0;
|
||||
bool lowspeed = false;
|
||||
|
||||
// poll underlaying hardware layer
|
||||
tmpdata = max3421e_poll();
|
||||
|
||||
/* modify USB task state if Vbus changed */
|
||||
switch( tmpdata ) {
|
||||
|
||||
// illegal state
|
||||
case MAX3421E_STATE_SE1:
|
||||
usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
|
||||
lowspeed = false;
|
||||
break;
|
||||
|
||||
// disconnected
|
||||
case MAX3421E_STATE_SE0:
|
||||
if(( usb_task_state & USB_STATE_MASK ) != USB_STATE_DETACHED )
|
||||
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
|
||||
lowspeed = false;
|
||||
break;
|
||||
|
||||
// attached
|
||||
case MAX3421E_STATE_LSHOST:
|
||||
lowspeed = true;
|
||||
// intentional fall-through ...
|
||||
|
||||
case MAX3421E_STATE_FSHOST:
|
||||
if(( usb_task_state & USB_STATE_MASK ) == USB_STATE_DETACHED ) {
|
||||
delay = timer_get_msec() + USB_SETTLE_DELAY;
|
||||
usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// max poll 1ms
|
||||
static msec_t poll=0;
|
||||
if(timer_get_msec() > poll) {
|
||||
poll = timer_get_msec()+1;
|
||||
|
||||
// poll all configured devices
|
||||
uint8_t i;
|
||||
for (i=0; i<USB_NUMDEVICES; i++)
|
||||
if(dev[i].bAddress)
|
||||
rcode = dev[i].class->poll(dev+i);
|
||||
|
||||
switch( usb_task_state ) {
|
||||
case USB_DETACHED_SUBSTATE_INITIALIZE:
|
||||
usb_reset_state();
|
||||
|
||||
// just remove everything ...
|
||||
for (i=0; i<USB_NUMDEVICES; i++) {
|
||||
if (dev[i].bAddress) {
|
||||
rcode = dev[i].class->release(dev+i);
|
||||
dev[i].bAddress = 0;
|
||||
}
|
||||
}
|
||||
|
||||
usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
|
||||
break;
|
||||
|
||||
case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE:
|
||||
case USB_DETACHED_SUBSTATE_ILLEGAL:
|
||||
break;
|
||||
|
||||
case USB_ATTACHED_SUBSTATE_SETTLE: //settle time for just attached device
|
||||
if( delay < timer_get_msec() )
|
||||
usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
|
||||
break;
|
||||
|
||||
case USB_ATTACHED_SUBSTATE_RESET_DEVICE:
|
||||
max3421e_write_u08( MAX3421E_HCTL, MAX3421E_BUSRST ); // issue bus reset
|
||||
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE;
|
||||
break;
|
||||
|
||||
case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE:
|
||||
if(( !max3421e_read_u08( MAX3421E_HCTL ) & MAX3421E_BUSRST ) ) {
|
||||
tmpdata = max3421e_read_u08( MAX3421E_MODE ) | MAX3421E_SOFKAENAB; // start SOF generation
|
||||
max3421e_write_u08( MAX3421E_MODE, tmpdata );
|
||||
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
|
||||
delay = timer_get_msec() + 20; //20ms wait after reset per USB spec
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order
|
||||
if( max3421e_read_u08( MAX3421E_HIRQ ) & MAX3421E_FRAMEIRQ ) { //when first SOF received we can continue
|
||||
if( delay < timer_get_msec() ) //20ms passed
|
||||
usb_task_state = USB_STATE_CONFIGURING;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_STATE_CONFIGURING:
|
||||
// configure root device
|
||||
usb_configure(0, 0, lowspeed);
|
||||
usb_task_state = USB_STATE_RUNNING;
|
||||
break;
|
||||
|
||||
case USB_STATE_RUNNING:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t usb_release_device(uint8_t parent, uint8_t port) {
|
||||
iprintf("%s(parent=%x, port=%d\n", __FUNCTION__, parent, port);
|
||||
|
||||
uint8_t i;
|
||||
for(i=0; i<USB_NUMDEVICES; i++) {
|
||||
if(dev[i].bAddress && dev[i].parent == parent && dev[i].port == port) {
|
||||
iprintf(" -> device with address %x\n", dev[i].bAddress);
|
||||
|
||||
// check if this is a hub (parent of some other device)
|
||||
// and release its kids first
|
||||
uint8_t j;
|
||||
for(j=0; j<USB_NUMDEVICES; j++) {
|
||||
if(dev[j].parent == dev[i].bAddress)
|
||||
usb_release_device(dev[i].bAddress, dev[j].port);
|
||||
}
|
||||
|
||||
uint8_t rcode = 0;
|
||||
if(dev[i].class)
|
||||
rcode = dev[i].class->release(dev+i);
|
||||
|
||||
dev[i].bAddress = 0;
|
||||
return rcode;
|
||||
}
|
||||
}
|
||||
|
||||
// this should never happen ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t usb_get_dev_descr( usb_device_t *dev, uint16_t nbytes, usb_device_descriptor_t* p ) {
|
||||
return( usb_ctrl_req( dev, USB_REQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR,
|
||||
0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, nbytes, (uint8_t*)p, NULL ));
|
||||
}
|
||||
|
||||
//get configuration descriptor
|
||||
uint8_t usb_get_conf_descr( usb_device_t *dev, uint16_t nbytes,
|
||||
uint8_t conf, usb_configuration_descriptor_t* p ) {
|
||||
return( usb_ctrl_req( dev, USB_REQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR,
|
||||
conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, nbytes, (uint8_t*)p, NULL ));
|
||||
}
|
||||
|
||||
uint8_t usb_set_addr( usb_device_t *dev, uint8_t newaddr ) {
|
||||
iprintf("%s(new=%x)\n", __FUNCTION__, newaddr);
|
||||
|
||||
uint8_t rcode = usb_ctrl_req( dev, USB_REQ_SET, USB_REQUEST_SET_ADDRESS, newaddr,
|
||||
0x00, 0x0000, 0x0000, 0x0000, NULL, NULL );
|
||||
if(!rcode) dev->bAddress = newaddr;
|
||||
return rcode;
|
||||
}
|
||||
|
||||
//set configuration
|
||||
uint8_t usb_set_conf( usb_device_t *dev, uint8_t conf_value ) {
|
||||
return( usb_ctrl_req( dev, USB_REQ_SET, USB_REQUEST_SET_CONFIGURATION,
|
||||
conf_value, 0x00, 0x0000, 0x0000, 0x0000, NULL, NULL ));
|
||||
}
|
||||
|
||||
void usb_SetHubPreMask() {
|
||||
bmHubPre |= MAX3421E_HUBPRE;
|
||||
};
|
||||
|
||||
void usb_ResetHubPreMask() {
|
||||
bmHubPre &= ~MAX3421E_HUBPRE;
|
||||
};
|
||||
250
usb/usb.h
Normal file
250
usb/usb.h
Normal file
@@ -0,0 +1,250 @@
|
||||
#ifndef USB_H
|
||||
#define USB_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* NAK powers. To save space in endpoint data structure, amount of retries */
|
||||
/* before giving up and returning 0x4 is stored in bmNakPower as a power of 2.*/
|
||||
/* The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
|
||||
#define USB_NAK_MAX_POWER 16 //NAK binary order maximum value
|
||||
#define USB_NAK_DEFAULT 14 //default 16K-1 NAKs before giving up
|
||||
#define USB_NAK_NOWAIT 1 //Single NAK stops transfer
|
||||
#define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout
|
||||
|
||||
typedef struct {
|
||||
uint8_t epAddr; // Endpoint address
|
||||
uint8_t maxPktSize; // Maximum packet size
|
||||
|
||||
union {
|
||||
uint8_t epAttribs;
|
||||
|
||||
struct {
|
||||
// Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
|
||||
uint8_t bmSndToggle: 1;
|
||||
// Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
|
||||
uint8_t bmRcvToggle: 1;
|
||||
// Binary order for NAK_LIMIT value
|
||||
uint8_t bmNakPower: 6;
|
||||
};
|
||||
};
|
||||
} ep_t;
|
||||
|
||||
#define USB_NUMDEVICES 16 // number of supported USB devices
|
||||
|
||||
/* Common setup data constant combinations */
|
||||
#define USB_REQ_GET_DESCR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //get descriptor request type
|
||||
#define USB_REQ_SET USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //set request type for all but 'set feature' and 'set interface'
|
||||
#define USB_REQ_CL_GET_INTF USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE //get interface request type
|
||||
|
||||
#define USB_SETTLE_DELAY 200 // settle delay in milliseconds
|
||||
#define USB_XFER_TIMEOUT 5000 // USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec
|
||||
#define USB_RETRY_LIMIT 3 // retry limit for a transfer
|
||||
|
||||
/* USB state machine states */
|
||||
#define USB_STATE_MASK 0xf0
|
||||
|
||||
#define USB_STATE_DETACHED 0x10
|
||||
#define USB_DETACHED_SUBSTATE_INITIALIZE 0x11
|
||||
#define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE 0x12
|
||||
#define USB_DETACHED_SUBSTATE_ILLEGAL 0x13
|
||||
#define USB_ATTACHED_SUBSTATE_SETTLE 0x20
|
||||
#define USB_ATTACHED_SUBSTATE_RESET_DEVICE 0x30
|
||||
#define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE 0x40
|
||||
#define USB_ATTACHED_SUBSTATE_WAIT_SOF 0x50
|
||||
#define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE 0x60
|
||||
#define USB_STATE_ADDRESSING 0x70
|
||||
#define USB_STATE_CONFIGURING 0x80
|
||||
#define USB_STATE_RUNNING 0x90
|
||||
|
||||
/* USB Setup Packet Structure */
|
||||
typedef struct {
|
||||
union { // offset description
|
||||
uint8_t bmRequestType; // 0 Bit-map of request type
|
||||
struct {
|
||||
uint8_t recipient: 5; // Recipient of the request
|
||||
uint8_t type: 2; // Type of request
|
||||
uint8_t direction: 1; // Direction of data X-fer
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed)) ReqType_u;
|
||||
uint8_t bRequest; // 1 Request
|
||||
union {
|
||||
uint16_t wValue; // 2/3 Depends on bRequest
|
||||
struct {
|
||||
uint8_t wValueLo;
|
||||
uint8_t wValueHi;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed)) wVal_u;
|
||||
uint16_t wIndex; // 4 Depends on bRequest
|
||||
uint16_t wLength; // 6 Depends on bRequest
|
||||
} __attribute__((packed)) setup_pkt_t;
|
||||
|
||||
// Additional Error Codes
|
||||
#define USB_ERROR_INVALID_MAX_PKT_SIZE 0xDA
|
||||
#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED 0xDB
|
||||
#define USB_ERROR_CONFIGURAION_SIZE_MISMATCH 0xDC
|
||||
#define USB_ERROR_TRANSFER_TIMEOUT 0xFF
|
||||
|
||||
struct usb_device_entry;
|
||||
|
||||
typedef struct {
|
||||
uint8_t (*init)(struct usb_device_entry *);
|
||||
uint8_t (*release)(struct usb_device_entry *);
|
||||
uint8_t (*poll)(struct usb_device_entry *);
|
||||
} usb_device_class_config_t;
|
||||
|
||||
#include "hub.h"
|
||||
#include "hid.h"
|
||||
|
||||
// entry used for list of connected devices
|
||||
typedef struct usb_device_entry {
|
||||
const usb_device_class_config_t *class; // pointer to class hadlers
|
||||
ep_t ep0; // information about endpoint 0
|
||||
uint8_t bAddress; // device address
|
||||
uint8_t parent; // parent device address
|
||||
uint8_t port;
|
||||
bool lowspeed;
|
||||
|
||||
union {
|
||||
usb_hub_info_t hub_info;
|
||||
usb_hid_info_t hid_info;
|
||||
};
|
||||
} usb_device_t;
|
||||
|
||||
#define USB_CLASS_USE_CLASS_INFO 0x00 // Use Class Info in the Interface Descriptors
|
||||
#define USB_CLASS_AUDIO 0x01 // Audio
|
||||
#define USB_CLASS_COM_AND_CDC_CTRL 0x02 // Communications and CDC Control
|
||||
#define USB_CLASS_HID 0x03 // HID
|
||||
#define USB_CLASS_PHYSICAL 0x05 // Physical
|
||||
#define USB_CLASS_IMAGE 0x06 // Image
|
||||
#define USB_CLASS_PRINTER 0x07 // Printer
|
||||
#define USB_CLASS_MASS_STORAGE 0x08 // Mass Storage
|
||||
#define USB_CLASS_HUB 0x09 // Hub
|
||||
#define USB_CLASS_CDC_DATA 0x0a // CDC-Data
|
||||
#define USB_CLASS_SMART_CARD 0x0b // Smart-Card
|
||||
#define USB_CLASS_CONTENT_SECURITY 0x0d // Content Security
|
||||
#define USB_CLASS_VIDEO 0x0e // Video
|
||||
#define USB_CLASS_PERSONAL_HEALTH 0x0f // Personal Healthcare
|
||||
#define USB_CLASS_DIAGNOSTIC_DEVICE 0xdc // Diagnostic Device
|
||||
#define USB_CLASS_WIRELESS_CTRL 0xe0 // Wireless Controller
|
||||
#define USB_CLASS_MISC 0xef // Miscellaneous
|
||||
#define USB_CLASS_APP_SPECIFIC 0xfe // Application Specific
|
||||
#define USB_CLASS_VENDOR_SPECIFIC 0xff // Vendor Specific
|
||||
|
||||
/*******************************************************************************/
|
||||
/*** ***/
|
||||
/*** USB chapter 9 structures ***/
|
||||
/*** ***/
|
||||
/*******************************************************************************/
|
||||
|
||||
/* Device descriptor structure */
|
||||
typedef struct {
|
||||
uint8_t bLength; // Length of this descriptor.
|
||||
uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE).
|
||||
uint16_t bcdUSB; // USB Spec Release Number (BCD).
|
||||
uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
|
||||
uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF).
|
||||
uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
|
||||
uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0.
|
||||
uint16_t idVendor; // Vendor ID (assigned by the USB-IF).
|
||||
uint16_t idProduct; // Product ID (assigned by the manufacturer).
|
||||
uint16_t bcdDevice; // Device release number (BCD).
|
||||
uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer.
|
||||
uint8_t iProduct; // Index of String Descriptor describing the product.
|
||||
uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number.
|
||||
uint8_t bNumConfigurations; // Number of possible configurations.
|
||||
} __attribute__((packed)) usb_device_descriptor_t;
|
||||
|
||||
/* Configuration descriptor structure */
|
||||
typedef struct {
|
||||
uint8_t bLength; // Length of this descriptor.
|
||||
uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION).
|
||||
uint16_t wTotalLength; // Total length of all descriptors for this configuration.
|
||||
uint8_t bNumInterfaces; // Number of interfaces in this configuration.
|
||||
uint8_t bConfigurationValue; // Value of this configuration (1 based).
|
||||
uint8_t iConfiguration; // Index of String Descriptor describing the configuration.
|
||||
uint8_t bmAttributes; // Configuration characteristics.
|
||||
uint8_t bMaxPower; // Maximum power consumed by this configuration.
|
||||
} __attribute__((packed)) usb_configuration_descriptor_t;
|
||||
|
||||
/* Interface descriptor structure */
|
||||
typedef struct {
|
||||
uint8_t bLength; // Length of this descriptor.
|
||||
uint8_t bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE).
|
||||
uint8_t bInterfaceNumber; // Number of this interface (0 based).
|
||||
uint8_t bAlternateSetting; // Value of this alternate interface setting.
|
||||
uint8_t bNumEndpoints; // Number of endpoints in this interface.
|
||||
uint8_t bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
|
||||
uint8_t bInterfaceSubClass; // Subclass code (assigned by the USB-IF).
|
||||
uint8_t bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
|
||||
uint8_t iInterface; // Index of String Descriptor describing the interface.
|
||||
} __attribute__((packed)) usb_interface_descriptor_t;
|
||||
|
||||
/* Endpoint descriptor structure */
|
||||
typedef struct {
|
||||
uint8_t bLength; // Length of this descriptor.
|
||||
uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT).
|
||||
uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN).
|
||||
uint8_t bmAttributes; // Endpoint transfer type.
|
||||
uint8_t wMaxPacketSize[2]; // Maximum packet size.
|
||||
uint8_t bInterval; // Polling interval in frames.
|
||||
} __attribute__((packed)) usb_endpoint_descriptor_t;
|
||||
|
||||
/* Standard Device Requests */
|
||||
#define USB_REQUEST_GET_STATUS 0 // Standard Device Request - GET STATUS
|
||||
#define USB_REQUEST_CLEAR_FEATURE 1 // Standard Device Request - CLEAR FEATURE
|
||||
#define USB_REQUEST_SET_FEATURE 3 // Standard Device Request - SET FEATURE
|
||||
#define USB_REQUEST_SET_ADDRESS 5 // Standard Device Request - SET ADDRESS
|
||||
#define USB_REQUEST_GET_DESCRIPTOR 6 // Standard Device Request - GET DESCRIPTOR
|
||||
#define USB_REQUEST_SET_DESCRIPTOR 7 // Standard Device Request - SET DESCRIPTOR
|
||||
#define USB_REQUEST_GET_CONFIGURATION 8 // Standard Device Request - GET CONFIGURATION
|
||||
#define USB_REQUEST_SET_CONFIGURATION 9 // Standard Device Request - SET CONFIGURATION
|
||||
#define USB_REQUEST_GET_INTERFACE 10 // Standard Device Request - GET INTERFACE
|
||||
#define USB_REQUEST_SET_INTERFACE 11 // Standard Device Request - SET INTERFACE
|
||||
#define USB_REQUEST_SYNCH_FRAME 12 // Standard Device Request - SYNCH FRAME
|
||||
|
||||
#define USB_FEATURE_ENDPOINT_HALT 0 // CLEAR/SET FEATURE - Endpoint Halt
|
||||
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // CLEAR/SET FEATURE - Device remote wake-up
|
||||
#define USB_FEATURE_TEST_MODE 2 // CLEAR/SET FEATURE - Test mode
|
||||
|
||||
/* Setup Data Constants */
|
||||
#define USB_SETUP_HOST_TO_DEVICE 0x00 // Device Request bmRequestType transfer direction - host to device transfer
|
||||
#define USB_SETUP_DEVICE_TO_HOST 0x80 // Device Request bmRequestType transfer direction - device to host transfer
|
||||
#define USB_SETUP_TYPE_STANDARD 0x00 // Device Request bmRequestType type - standard
|
||||
#define USB_SETUP_TYPE_CLASS 0x20 // Device Request bmRequestType type - class
|
||||
#define USB_SETUP_TYPE_VENDOR 0x40 // Device Request bmRequestType type - vendor
|
||||
#define USB_SETUP_RECIPIENT_DEVICE 0x00 // Device Request bmRequestType recipient - device
|
||||
#define USB_SETUP_RECIPIENT_INTERFACE 0x01 // Device Request bmRequestType recipient - interface
|
||||
#define USB_SETUP_RECIPIENT_ENDPOINT 0x02 // Device Request bmRequestType recipient - endpoint
|
||||
#define USB_SETUP_RECIPIENT_OTHER 0x03 // Device Request bmRequestType recipient - other
|
||||
|
||||
/* USB descriptors */
|
||||
#define USB_DESCRIPTOR_DEVICE 0x01 // bDescriptorType for a Device Descriptor.
|
||||
#define USB_DESCRIPTOR_CONFIGURATION 0x02 // bDescriptorType for a Configuration Descriptor.
|
||||
#define USB_DESCRIPTOR_STRING 0x03 // bDescriptorType for a String Descriptor.
|
||||
#define USB_DESCRIPTOR_INTERFACE 0x04 // bDescriptorType for an Interface Descriptor.
|
||||
#define USB_DESCRIPTOR_ENDPOINT 0x05 // bDescriptorType for an Endpoint Descriptor.
|
||||
#define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06 // bDescriptorType for a Device Qualifier.
|
||||
#define USB_DESCRIPTOR_OTHER_SPEED 0x07 // bDescriptorType for a Other Speed Configuration.
|
||||
#define USB_DESCRIPTOR_INTERFACE_POWER 0x08 // bDescriptorType for Interface Power.
|
||||
|
||||
typedef void(*usb_parser_t)(const uint16_t, const uint8_t *, const uint16_t);
|
||||
|
||||
void usb_init();
|
||||
void usb_poll();
|
||||
void usb_SetHubPreMask(void);
|
||||
void usb_ResetHubPreMask(void);
|
||||
|
||||
uint8_t usb_set_addr( usb_device_t *, uint8_t );
|
||||
uint8_t usb_ctrl_req( usb_device_t *, uint8_t bmReqType,
|
||||
uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
|
||||
uint16_t wInd, uint16_t total, uint16_t nbytes,
|
||||
uint8_t* dataptr, usb_parser_t *p);
|
||||
uint8_t usb_get_dev_descr( usb_device_t *, uint16_t nbytes, usb_device_descriptor_t* dataptr );
|
||||
uint8_t usb_get_conf_descr( usb_device_t *, uint16_t nbytes, uint8_t conf, usb_configuration_descriptor_t* dataptr );
|
||||
uint8_t usb_set_conf( usb_device_t *dev, uint8_t conf_value );
|
||||
uint8_t usb_in_transfer( usb_device_t *, ep_t *ep, uint16_t *nbytesptr, uint8_t* data);
|
||||
uint8_t usb_release_device(uint8_t parent, uint8_t port);
|
||||
usb_device_t *usb_get_devices();
|
||||
|
||||
#endif // USB_H
|
||||
732
user_io.c
Normal file
732
user_io.c
Normal file
@@ -0,0 +1,732 @@
|
||||
/*
|
||||
|
||||
https://www.kernel.org/doc/Documentation/input/atarikbd.txt
|
||||
|
||||
ikbd ToDo:
|
||||
|
||||
Feature Example using/needing it impl. tested
|
||||
---------------------------------------------------------------------
|
||||
mouse y at bottom Bolo X X
|
||||
mouse button key events Goldrunner/Automation 8 X X
|
||||
joystick interrogation mode ?
|
||||
Absolute mouse mode Backlash/Automation 8
|
||||
disable mouse ? X
|
||||
disable joystick ? X
|
||||
Joysticks also generate Goldrunner
|
||||
mouse button events!
|
||||
|
||||
*/
|
||||
|
||||
#include "AT91SAM7S256.h"
|
||||
#include "stdio.h"
|
||||
#include "hardware.h"
|
||||
|
||||
#include "user_io.h"
|
||||
#include "usb.h"
|
||||
|
||||
#include "keycodes.h"
|
||||
|
||||
typedef enum { EMU_NONE, EMU_MOUSE, EMU_JOY0, EMU_JOY1 } emu_mode_t;
|
||||
static emu_mode_t emu_mode = EMU_NONE;
|
||||
static unsigned char emu_state = 0;
|
||||
static long emu_timer;
|
||||
#define EMU_MOUSE_FREQ 5
|
||||
|
||||
static unsigned char core_type = CORE_TYPE_UNKNOWN;
|
||||
|
||||
AT91PS_ADC a_pADC = AT91C_BASE_ADC;
|
||||
AT91PS_PMC a_pPMC = AT91C_BASE_PMC;
|
||||
|
||||
static char caps_lock_toggle = 0;
|
||||
|
||||
// atari ikbd stuff
|
||||
#define IKBD_STATE_JOYSTICK_EVENT_REPORTING 0x01
|
||||
#define IKBD_STATE_MOUSE_Y_BOTTOM 0x02
|
||||
#define IKBD_STATE_MOUSE_BUTTON_AS_KEY 0x04 // mouse buttons act like keys
|
||||
#define IKBD_STATE_MOUSE_DISABLED 0x08
|
||||
|
||||
#define IKBD_DEFAULT IKBD_STATE_JOYSTICK_EVENT_REPORTING
|
||||
|
||||
static unsigned char ikbd_cmd = 0;
|
||||
static unsigned char ikbd_state = IKBD_DEFAULT;
|
||||
static unsigned char ikbd_expect = 0;
|
||||
static unsigned char ikbd_joystick_buttons = 0;
|
||||
|
||||
// #define IKBD_DEBUG
|
||||
|
||||
void ikbd_ok() {
|
||||
// this only happens while we are reading
|
||||
// from the spi. so stop reading
|
||||
DisableIO();
|
||||
|
||||
// send reply
|
||||
EnableIO();
|
||||
SPI(UIO_IKBD_OUT);
|
||||
SPI(0xf0);
|
||||
DisableIO();
|
||||
|
||||
// continue reading
|
||||
EnableIO();
|
||||
SPI(UIO_IKBD_IN);
|
||||
}
|
||||
|
||||
// process inout from atari core into ikbd
|
||||
void ikbd_handle_input(unsigned char cmd) {
|
||||
// expecting a second byte for command
|
||||
if(ikbd_expect) {
|
||||
ikbd_expect--;
|
||||
|
||||
// last byte of command received
|
||||
if(!ikbd_expect) {
|
||||
switch(ikbd_cmd) {
|
||||
case 0x07: // set mouse button action
|
||||
iprintf("mouse button action = %x\n", cmd);
|
||||
|
||||
// bit 2: Mouse buttons act like keys (LEFT=0x74 & RIGHT=0x75)
|
||||
if(cmd & 0x04) ikbd_state |= IKBD_STATE_MOUSE_BUTTON_AS_KEY;
|
||||
else ikbd_state &= ~IKBD_STATE_MOUSE_BUTTON_AS_KEY;
|
||||
|
||||
break;
|
||||
|
||||
case 0x80: // ibkd reset
|
||||
// reply "everything is ok"
|
||||
ikbd_ok();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ikbd_cmd = cmd;
|
||||
|
||||
switch(cmd) {
|
||||
case 0x07:
|
||||
puts("IKBD: Set mouse button action");
|
||||
ikbd_expect = 1;
|
||||
break;
|
||||
|
||||
case 0x08:
|
||||
puts("IKBD: Set relative mouse positioning");
|
||||
ikbd_state &= ~IKBD_STATE_MOUSE_DISABLED;
|
||||
break;
|
||||
|
||||
case 0x0b:
|
||||
puts("IKBD: Set Mouse threshold");
|
||||
ikbd_expect = 2;
|
||||
break;
|
||||
|
||||
case 0x0f:
|
||||
puts("IKBD: Set Y at bottom");
|
||||
ikbd_state |= IKBD_STATE_MOUSE_Y_BOTTOM;
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
puts("IKBD: Set Y at top");
|
||||
ikbd_state &= ~IKBD_STATE_MOUSE_Y_BOTTOM;
|
||||
break;
|
||||
|
||||
case 0x12:
|
||||
puts("IKBD: Disable mouse");
|
||||
ikbd_state |= IKBD_STATE_MOUSE_DISABLED;
|
||||
break;
|
||||
|
||||
case 0x14:
|
||||
puts("IKBD: Set Joystick event reporting");
|
||||
ikbd_state |= IKBD_STATE_JOYSTICK_EVENT_REPORTING;
|
||||
break;
|
||||
|
||||
case 0x15:
|
||||
puts("IKBD: Set Joystick interrogation mode");
|
||||
ikbd_state &= ~IKBD_STATE_JOYSTICK_EVENT_REPORTING;
|
||||
break;
|
||||
|
||||
case 0x1a:
|
||||
puts("IKBD: Disable joysticks");
|
||||
ikbd_state &= ~IKBD_STATE_JOYSTICK_EVENT_REPORTING;
|
||||
break;
|
||||
|
||||
case 0x1c:
|
||||
puts("IKBD: Interrogate time of day");
|
||||
|
||||
// send some date
|
||||
|
||||
// stop reading from ikbd queue
|
||||
DisableIO();
|
||||
|
||||
// send reply (the date this routine was written)
|
||||
EnableIO();
|
||||
SPI(UIO_IKBD_OUT);
|
||||
SPI(0xfc);
|
||||
SPI(0x13); // year bcd
|
||||
SPI(0x03); // month bcd
|
||||
SPI(0x07); // day bcd
|
||||
SPI(0x20); // hour bcd
|
||||
SPI(0x58); // minute bcd
|
||||
SPI(0x00); // second bcd
|
||||
DisableIO();
|
||||
|
||||
// continue reading
|
||||
EnableIO();
|
||||
SPI(UIO_IKBD_IN);
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case 0x80:
|
||||
puts("IKBD: Reset");
|
||||
ikbd_expect = 1;
|
||||
ikbd_state = IKBD_DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
iprintf("IKBD: unknown command: %x\n", cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void InitADC(void) {
|
||||
|
||||
// Enable clock for interface
|
||||
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_ADC;
|
||||
|
||||
// Reset
|
||||
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST;
|
||||
AT91C_BASE_ADC->ADC_CR = 0x0;
|
||||
|
||||
// Set maximum startup time and hold time
|
||||
AT91C_BASE_ADC->ADC_MR = 0x0F1F0F00 | AT91C_ADC_LOWRES_8_BIT;
|
||||
}
|
||||
|
||||
static unsigned int GetAdc(unsigned char channel) {
|
||||
|
||||
// variable
|
||||
unsigned int result;
|
||||
|
||||
// Enable desired chanel
|
||||
AT91C_BASE_ADC->ADC_CHER = channel;
|
||||
|
||||
// Start conversion
|
||||
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
|
||||
|
||||
// wait for end of convertion
|
||||
while(!(AT91C_BASE_ADC->ADC_SR & channel));
|
||||
|
||||
switch (channel) {
|
||||
case AT91C_ADC_CH4: result = AT91C_BASE_ADC->ADC_CDR4; break;
|
||||
case AT91C_ADC_CH5: result = AT91C_BASE_ADC->ADC_CDR5; break;
|
||||
case AT91C_ADC_CH6: result = AT91C_BASE_ADC->ADC_CDR6; break;
|
||||
case AT91C_ADC_CH7: result = AT91C_BASE_ADC->ADC_CDR7; break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void user_io_init() {
|
||||
InitADC();
|
||||
|
||||
}
|
||||
|
||||
unsigned char user_io_core_type() {
|
||||
return core_type;
|
||||
}
|
||||
|
||||
void user_io_detect_core_type() {
|
||||
EnableIO();
|
||||
core_type = SPI(0xff);
|
||||
DisableIO();
|
||||
|
||||
if((core_type != CORE_TYPE_DUMB) &&
|
||||
(core_type != CORE_TYPE_MINIMIG) &&
|
||||
(core_type != CORE_TYPE_PACE) &&
|
||||
(core_type != CORE_TYPE_MIST))
|
||||
core_type = CORE_TYPE_UNKNOWN;
|
||||
|
||||
switch(core_type) {
|
||||
case CORE_TYPE_UNKNOWN:
|
||||
puts("Unable to identify core!");
|
||||
break;
|
||||
|
||||
case CORE_TYPE_DUMB:
|
||||
puts("Identified core without user interface");
|
||||
break;
|
||||
|
||||
case CORE_TYPE_MINIMIG:
|
||||
puts("Identified Minimig core");
|
||||
break;
|
||||
|
||||
case CORE_TYPE_PACE:
|
||||
puts("Identified PACE core");
|
||||
break;
|
||||
|
||||
case CORE_TYPE_MIST:
|
||||
puts("Identified MiST core");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// convert internal joystick format into atari ikbd format
|
||||
unsigned char joystick_map2ikbd(unsigned in) {
|
||||
unsigned char out = 0;
|
||||
|
||||
if(in & JOY_UP) out |= 0x01;
|
||||
if(in & JOY_DOWN) out |= 0x02;
|
||||
if(in & JOY_LEFT) out |= 0x04;
|
||||
if(in & JOY_RIGHT) out |= 0x08;
|
||||
if(in & JOY_BTN1) out |= 0x80;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void user_io_joystick(unsigned char joystick, unsigned char map) {
|
||||
if(core_type == CORE_TYPE_MINIMIG) {
|
||||
EnableIO();
|
||||
SPI(UIO_JOYSTICK0 + joystick);
|
||||
SPI(map);
|
||||
DisableIO();
|
||||
}
|
||||
|
||||
if(core_type == CORE_TYPE_MIST) {
|
||||
// todo: suppress events for joystick 0 as long as mouse
|
||||
// is enabled?
|
||||
|
||||
if(ikbd_state & IKBD_STATE_JOYSTICK_EVENT_REPORTING) {
|
||||
#ifdef IKBD_DEBUG
|
||||
iprintf("IKBD: joy %d %x\n", joystick, map);
|
||||
#endif
|
||||
|
||||
EnableIO();
|
||||
SPI(UIO_IKBD_OUT);
|
||||
SPI(0xfe + joystick);
|
||||
SPI(joystick_map2ikbd(map));
|
||||
DisableIO();
|
||||
|
||||
// the fire button also generates a mouse event if
|
||||
// mouse reporting is enabled
|
||||
|
||||
unsigned char button1 = (map & JOY_BTN1)?(1<<joystick):0;
|
||||
if(button1 != (ikbd_joystick_buttons & (1<<joystick))) {
|
||||
// update saved state of joystick buttons
|
||||
ikbd_joystick_buttons = (ikbd_joystick_buttons & ~(1<<joystick)) | button1;
|
||||
|
||||
// generate mouse event (ikbd_joystick_buttons is evaluated inside
|
||||
// user_io_mouse)
|
||||
user_io_mouse(0, 0, 0);
|
||||
}
|
||||
}
|
||||
#ifdef IKBD_DEBUG
|
||||
else
|
||||
iprintf("IKBD: no monitor, drop joy %d %x\n", joystick, map);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void user_io_poll() {
|
||||
if((core_type != CORE_TYPE_MINIMIG) &&
|
||||
(core_type != CORE_TYPE_PACE) &&
|
||||
(core_type != CORE_TYPE_MIST)) {
|
||||
return; // no user io for the installed core
|
||||
}
|
||||
|
||||
if(core_type == CORE_TYPE_MIST) {
|
||||
static mtimer = 0;
|
||||
if(CheckTimer(mtimer)) {
|
||||
mtimer = GetTimer(100);
|
||||
|
||||
// check for incoming ikbd data
|
||||
EnableIO();
|
||||
SPI(UIO_IKBD_IN);
|
||||
|
||||
while(SPI(0))
|
||||
ikbd_handle_input(SPI(0));
|
||||
|
||||
DisableIO();
|
||||
|
||||
// check for incoming serial data
|
||||
EnableIO();
|
||||
SPI(UIO_SERIAL_IN);
|
||||
|
||||
while(SPI(0))
|
||||
putchar(SPI(0));
|
||||
|
||||
DisableIO();
|
||||
}
|
||||
}
|
||||
|
||||
// poll db9 joysticks
|
||||
static int joy0_state = JOY0;
|
||||
if((*AT91C_PIOA_PDSR & JOY0) != joy0_state) {
|
||||
joy0_state = *AT91C_PIOA_PDSR & JOY0;
|
||||
|
||||
unsigned char joy_map = 0;
|
||||
if(!(joy0_state & JOY0_UP)) joy_map |= JOY_UP;
|
||||
if(!(joy0_state & JOY0_DOWN)) joy_map |= JOY_DOWN;
|
||||
if(!(joy0_state & JOY0_LEFT)) joy_map |= JOY_LEFT;
|
||||
if(!(joy0_state & JOY0_RIGHT)) joy_map |= JOY_RIGHT;
|
||||
if(!(joy0_state & JOY0_BTN1)) joy_map |= JOY_BTN1;
|
||||
if(!(joy0_state & JOY0_BTN2)) joy_map |= JOY_BTN2;
|
||||
|
||||
user_io_joystick(0, joy_map);
|
||||
}
|
||||
|
||||
static int joy1_state = JOY1;
|
||||
if((*AT91C_PIOA_PDSR & JOY1) != joy1_state) {
|
||||
joy1_state = *AT91C_PIOA_PDSR & JOY1;
|
||||
|
||||
unsigned char joy_map = 0;
|
||||
if(!(joy1_state & JOY1_UP)) joy_map |= JOY_UP;
|
||||
if(!(joy1_state & JOY1_DOWN)) joy_map |= JOY_DOWN;
|
||||
if(!(joy1_state & JOY1_LEFT)) joy_map |= JOY_LEFT;
|
||||
if(!(joy1_state & JOY1_RIGHT)) joy_map |= JOY_RIGHT;
|
||||
if(!(joy1_state & JOY1_BTN1)) joy_map |= JOY_BTN1;
|
||||
if(!(joy1_state & JOY1_BTN2)) joy_map |= JOY_BTN2;
|
||||
|
||||
user_io_joystick(1, joy_map);
|
||||
}
|
||||
|
||||
static unsigned char key_map = 0;
|
||||
unsigned char map = 0;
|
||||
if(GetAdc(AT91C_ADC_CH4) < 128) map |= SWITCH2;
|
||||
|
||||
if(GetAdc(AT91C_ADC_CH5) < 128) map |= SWITCH1;
|
||||
if(GetAdc(AT91C_ADC_CH6) < 128) map |= BUTTON1;
|
||||
if(GetAdc(AT91C_ADC_CH7) < 128) map |= BUTTON2;
|
||||
|
||||
if(map != key_map) {
|
||||
key_map = map;
|
||||
|
||||
EnableIO();
|
||||
SPI(UIO_BUT_SW);
|
||||
SPI(map);
|
||||
DisableIO();
|
||||
}
|
||||
|
||||
// mouse movement emulation is continous
|
||||
if(emu_mode == EMU_MOUSE) {
|
||||
if(CheckTimer(emu_timer)) {
|
||||
emu_timer = GetTimer(EMU_MOUSE_FREQ);
|
||||
|
||||
if(emu_state & JOY_MOVE) {
|
||||
unsigned char b = 0;
|
||||
char x = 0, y = 0;
|
||||
if((emu_state & (JOY_LEFT | JOY_RIGHT)) == JOY_LEFT) x = -1;
|
||||
if((emu_state & (JOY_LEFT | JOY_RIGHT)) == JOY_RIGHT) x = +1;
|
||||
if((emu_state & (JOY_UP | JOY_DOWN)) == JOY_UP) y = -1;
|
||||
if((emu_state & (JOY_UP | JOY_DOWN)) == JOY_DOWN) y = +1;
|
||||
|
||||
if(emu_state & JOY_BTN1) b |= 1;
|
||||
if(emu_state & JOY_BTN2) b |= 2;
|
||||
|
||||
user_io_mouse(b, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(core_type == CORE_TYPE_MIST) {
|
||||
// do some tos specific monitoring here
|
||||
tos_show_state();
|
||||
}
|
||||
}
|
||||
|
||||
int user_io_button_pressed() {
|
||||
return (GetAdc(AT91C_ADC_CH5) < 128);
|
||||
}
|
||||
|
||||
static void send_keycode(unsigned short code) {
|
||||
if(core_type == CORE_TYPE_MINIMIG) {
|
||||
EnableIO();
|
||||
if(code & OSD) SPI(UIO_KBD_OSD); // code for OSD
|
||||
else SPI(UIO_KEYBOARD);
|
||||
SPI(code & 0xff);
|
||||
DisableIO();
|
||||
}
|
||||
|
||||
if(core_type == CORE_TYPE_MIST) {
|
||||
#ifdef IKBD_DEBUG
|
||||
iprintf("IKBD: send keycode %x%s\n", code&0x7f, (code&0x80)?" BREAK":"");
|
||||
#endif
|
||||
EnableIO();
|
||||
SPI(UIO_IKBD_OUT);
|
||||
SPI(code & 0xff);
|
||||
DisableIO();
|
||||
}
|
||||
}
|
||||
|
||||
void user_io_mouse(unsigned char b, char x, char y) {
|
||||
|
||||
// send mouse data as minimig expects it
|
||||
if(core_type == CORE_TYPE_MINIMIG) {
|
||||
EnableIO();
|
||||
SPI(UIO_MOUSE);
|
||||
SPI(x);
|
||||
SPI(y);
|
||||
SPI(b);
|
||||
DisableIO();
|
||||
}
|
||||
|
||||
// send mouse data as mist expects it
|
||||
if(core_type == CORE_TYPE_MIST) {
|
||||
if(ikbd_state & IKBD_STATE_MOUSE_DISABLED)
|
||||
return;
|
||||
|
||||
// joystick and mouse buttons are wired together in
|
||||
// atari st
|
||||
b |= ikbd_joystick_buttons;
|
||||
|
||||
static unsigned char b_old = 0;
|
||||
// monitor state of two mouse buttons
|
||||
if(b != b_old) {
|
||||
// check if mouse buttons are supposed to be treated like keys
|
||||
if(ikbd_state & IKBD_STATE_MOUSE_BUTTON_AS_KEY) {
|
||||
// Mouse buttons act like keys (LEFT=0x74 & RIGHT=0x75)
|
||||
|
||||
// handle left mouse button
|
||||
if((b ^ b_old) & 1) send_keycode(0x74 | ((b&1)?0x00:0x80));
|
||||
// handle right mouse button
|
||||
if((b ^ b_old) & 2) send_keycode(0x75 | ((b&2)?0x00:0x80));
|
||||
}
|
||||
b_old = b;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if(ikbd_state & IKBD_STATE_MOUSE_BUTTON_AS_KEY) {
|
||||
b = 0;
|
||||
// if mouse position is 0/0 quit here
|
||||
if(!x && !y) return;
|
||||
}
|
||||
#endif
|
||||
|
||||
EnableIO();
|
||||
SPI(UIO_IKBD_OUT);
|
||||
// atari has mouse button bits swapped
|
||||
SPI(0xf8|((b&1)?2:0)|((b&2)?1:0));
|
||||
SPI(x);
|
||||
SPI((ikbd_state & IKBD_STATE_MOUSE_Y_BOTTOM)?-y:y);
|
||||
DisableIO();
|
||||
}
|
||||
}
|
||||
|
||||
// check if this is a key that's supposed to be suppressed
|
||||
// when emulation is active
|
||||
static unsigned char is_emu_key(unsigned char c) {
|
||||
static const unsigned char m[] = { JOY_RIGHT, JOY_LEFT, JOY_DOWN, JOY_UP };
|
||||
|
||||
if(emu_mode == EMU_NONE)
|
||||
return 0;
|
||||
|
||||
// direction keys R/L/D/U
|
||||
if(c >= 0x4f && c <= 0x52)
|
||||
return m[c-0x4f];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define EMU_BTN1 0 // left control
|
||||
#define EMU_BTN2 4 // right control
|
||||
|
||||
unsigned short keycode(unsigned char in) {
|
||||
if(core_type == CORE_TYPE_MINIMIG)
|
||||
return usb2ami[in];
|
||||
|
||||
if(core_type == CORE_TYPE_MIST)
|
||||
return usb2atari[in];
|
||||
|
||||
return MISS;
|
||||
}
|
||||
|
||||
unsigned char modifier_keycode(unsigned char index) {
|
||||
/* usb modifer bits:
|
||||
0 1 2 3 4 5 6 7
|
||||
LCTRL LSHIFT LALT LGUI RCTRL RSHIFT RALT RGUI
|
||||
*/
|
||||
|
||||
if(core_type == CORE_TYPE_MINIMIG) {
|
||||
static const unsigned char amiga_modifier[] =
|
||||
{ 0x63, 0x60, 0x64, 0x66, 0x63, 0x61, 0x65, 0x67 };
|
||||
return amiga_modifier[index];
|
||||
}
|
||||
|
||||
if(core_type == CORE_TYPE_MIST) {
|
||||
static const unsigned char atari_modifier[] =
|
||||
{ 0x1d, 0x2a, 0x38, MISS, 0x1d, 0x36, 0x38, MISS };
|
||||
return atari_modifier[index];
|
||||
}
|
||||
|
||||
return MISS;
|
||||
}
|
||||
|
||||
unsigned char osdcode(unsigned char c) {
|
||||
int i = 0;
|
||||
while(usb2osd[i][0] && usb2osd[i][0] != c)
|
||||
i++;
|
||||
|
||||
if(!usb2osd[i][0])
|
||||
iprintf("ERROR: Unsupported OSD code %x!\n", c);
|
||||
|
||||
return usb2osd[i][1];
|
||||
}
|
||||
|
||||
// set by OSD code to suppress forwarding of those keys to the core which
|
||||
// may be in use by an active OSD
|
||||
static char osd_eats_keys = false;
|
||||
|
||||
void user_io_osd_key_enable(char on) {
|
||||
osd_eats_keys = on;
|
||||
}
|
||||
|
||||
static char key_used_by_osd(unsigned short s) {
|
||||
if((s & OSD_LOC) && !(s & 0xff)) return true; // this key is only used in OSD and has no keycode
|
||||
if(!osd_eats_keys) return false; // OSD currently doesn't use keyboard
|
||||
return((s & OSD_LOC) != 0);
|
||||
}
|
||||
|
||||
void user_io_kbd(unsigned char m, unsigned char *k) {
|
||||
|
||||
if((core_type == CORE_TYPE_MINIMIG) ||
|
||||
(core_type == CORE_TYPE_MIST)) {
|
||||
|
||||
static unsigned char modifier = 0, pressed[6] = { 0,0,0,0,0,0 };
|
||||
int i, j;
|
||||
|
||||
// modifier keys are used as buttons in emu mode
|
||||
if(emu_mode != EMU_NONE) {
|
||||
char last_btn = emu_state & (JOY_BTN1 | JOY_BTN2);
|
||||
if(m & (1<<EMU_BTN1)) emu_state |= JOY_BTN1;
|
||||
else emu_state &= ~JOY_BTN1;
|
||||
if(m & (1<<EMU_BTN2)) emu_state |= JOY_BTN2;
|
||||
else emu_state &= ~JOY_BTN2;
|
||||
|
||||
// check if state of mouse buttons has changed
|
||||
if(last_btn != (emu_state & (JOY_BTN1 | JOY_BTN2))) {
|
||||
if(emu_mode == EMU_MOUSE) {
|
||||
unsigned char b;
|
||||
if(emu_state & JOY_BTN1) b |= 1;
|
||||
if(emu_state & JOY_BTN2) b |= 2;
|
||||
user_io_mouse(b, 0, 0);
|
||||
}
|
||||
|
||||
if(emu_mode == EMU_JOY0)
|
||||
user_io_joystick(0, emu_state);
|
||||
|
||||
if(emu_mode == EMU_JOY1)
|
||||
user_io_joystick(1, emu_state);
|
||||
}
|
||||
}
|
||||
|
||||
// handle modifier keys
|
||||
if(m != modifier) {
|
||||
for(i=0;i<8;i++) {
|
||||
if((m & (1<<i)) && !(modifier & (1<<i)))
|
||||
// shift keys are used for mouse joystick emulation in emu mode
|
||||
if(((i != EMU_BTN1) && (i != EMU_BTN2)) || (emu_mode == EMU_NONE))
|
||||
if(modifier_keycode(i) != MISS)
|
||||
send_keycode(modifier_keycode(i));
|
||||
|
||||
if(!(m & (1<<i)) && (modifier & (1<<i)))
|
||||
if(((i != EMU_BTN1) && (i != EMU_BTN2)) || (emu_mode == EMU_NONE))
|
||||
if(modifier_keycode(i) != MISS)
|
||||
send_keycode(0x80 | modifier_keycode(i));
|
||||
}
|
||||
|
||||
modifier = m;
|
||||
}
|
||||
|
||||
// check if there are keys in the pressed list which aren't
|
||||
// reported anymore
|
||||
for(i=0;i<6;i++) {
|
||||
unsigned short code = keycode(pressed[i]);
|
||||
|
||||
if(pressed[i] && code != MISS) {
|
||||
for(j=0;j<6 && pressed[i] != k[j];j++);
|
||||
|
||||
// don't send break for caps lock
|
||||
if(j == 6) {
|
||||
// special OSD key handled internally
|
||||
if(code & OSD_LOC)
|
||||
OsdKeySet(0x80 | osdcode(pressed[i]));
|
||||
|
||||
if(!key_used_by_osd(code)) {
|
||||
if(is_emu_key(pressed[i])) {
|
||||
emu_state &= ~is_emu_key(pressed[i]);
|
||||
|
||||
if(emu_mode == EMU_JOY0)
|
||||
user_io_joystick(0, emu_state);
|
||||
|
||||
if(emu_mode == EMU_JOY1)
|
||||
user_io_joystick(1, emu_state);
|
||||
} else if(!(code & CAPS_LOCK_TOGGLE) &&
|
||||
!(code & NUM_LOCK_TOGGLE))
|
||||
send_keycode(0x80 | code);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0;i<6;i++) {
|
||||
unsigned short code = keycode(k[i]);
|
||||
|
||||
if(k[i] && (k[i] <= KEYCODE_MAX) && code != MISS) {
|
||||
// check if this key is already in the list of pressed keys
|
||||
for(j=0;j<6 && k[i] != pressed[j];j++);
|
||||
|
||||
if(j == 6) {
|
||||
// special OSD key handled internally
|
||||
if(code & OSD_LOC)
|
||||
OsdKeySet(osdcode(k[i]));
|
||||
|
||||
// no further processing of any key that is currently
|
||||
// redirected to the OSD
|
||||
if(!key_used_by_osd(code)) {
|
||||
if (is_emu_key(k[i])) {
|
||||
emu_state |= is_emu_key(k[i]);
|
||||
|
||||
if(emu_mode == EMU_JOY0)
|
||||
user_io_joystick(0, emu_state);
|
||||
|
||||
if(emu_mode == EMU_JOY1)
|
||||
user_io_joystick(1, emu_state);
|
||||
} else if(!(code & CAPS_LOCK_TOGGLE)&&
|
||||
!(code & NUM_LOCK_TOGGLE))
|
||||
send_keycode(code);
|
||||
else {
|
||||
if(code & CAPS_LOCK_TOGGLE) {
|
||||
// send alternating make and break codes for caps lock
|
||||
send_keycode((code & 0xff) | (caps_lock_toggle?0x80:0));
|
||||
caps_lock_toggle = !caps_lock_toggle;
|
||||
|
||||
hid_set_kbd_led(HID_LED_CAPS_LOCK, caps_lock_toggle);
|
||||
}
|
||||
if(code & NUM_LOCK_TOGGLE) {
|
||||
// num lock has four states indicated by leds:
|
||||
// all off: normal
|
||||
// num lock on, scroll lock on: mouse emu
|
||||
// num lock on, scroll lock off: joy0 emu
|
||||
// num lock off, scroll lock on: joy1 emu
|
||||
|
||||
if(emu_mode == EMU_MOUSE)
|
||||
emu_timer = GetTimer(EMU_MOUSE_FREQ);
|
||||
|
||||
emu_mode = (emu_mode+1)&3;
|
||||
if(emu_mode == EMU_MOUSE || emu_mode == EMU_JOY0)
|
||||
hid_set_kbd_led(HID_LED_NUM_LOCK, true);
|
||||
else
|
||||
hid_set_kbd_led(HID_LED_NUM_LOCK, false);
|
||||
|
||||
if(emu_mode == EMU_MOUSE || emu_mode == EMU_JOY1)
|
||||
hid_set_kbd_led(HID_LED_SCROLL_LOCK, true);
|
||||
else
|
||||
hid_set_kbd_led(HID_LED_SCROLL_LOCK, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0;i<6;i++)
|
||||
pressed[i] = k[i];
|
||||
}
|
||||
}
|
||||
56
user_io.h
Normal file
56
user_io.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* user_io.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef USER_IO_H
|
||||
#define USER_IO_H
|
||||
|
||||
#define UIO_STATUS 0x00
|
||||
#define UIO_BUT_SW 0x01
|
||||
|
||||
// codes as used by minimig (amiga)
|
||||
#define UIO_JOYSTICK0 0x02
|
||||
#define UIO_JOYSTICK1 0x03
|
||||
#define UIO_MOUSE 0x04
|
||||
#define UIO_KEYBOARD 0x05
|
||||
#define UIO_KBD_OSD 0x06 // keycodes used by OSD only
|
||||
|
||||
// codes as used by MiST (atari)
|
||||
#define UIO_IKBD_OUT 0x02
|
||||
#define UIO_IKBD_IN 0x03
|
||||
#define UIO_SERIAL_OUT 0x04
|
||||
#define UIO_SERIAL_IN 0x05
|
||||
|
||||
#define JOY_RIGHT 0x01
|
||||
#define JOY_LEFT 0x02
|
||||
#define JOY_DOWN 0x04
|
||||
#define JOY_UP 0x08
|
||||
#define JOY_BTN1 0x10
|
||||
#define JOY_BTN2 0x20
|
||||
#define JOY_MOVE (JOY_RIGHT|JOY_LEFT|JOY_UP|JOY_DOWN)
|
||||
|
||||
#define BUTTON1 0x01
|
||||
#define BUTTON2 0x02
|
||||
#define SWITCH1 0x04
|
||||
#define SWITCH2 0x08
|
||||
|
||||
// core type value should be unlikely to be returned by broken cores
|
||||
#define CORE_TYPE_UNKNOWN 0x55
|
||||
#define CORE_TYPE_DUMB 0xa0
|
||||
#define CORE_TYPE_MINIMIG 0xa1
|
||||
#define CORE_TYPE_PACE 0xa2
|
||||
#define CORE_TYPE_MIST 0xa3
|
||||
|
||||
void user_io_init();
|
||||
void user_io_detect_core_type();
|
||||
unsigned char user_io_core_type();
|
||||
void user_io_poll();
|
||||
int user_io_button_pressed();
|
||||
void user_io_osd_key_enable(char);
|
||||
|
||||
// hooks from the usb layer
|
||||
void user_io_mouse(unsigned char b, char x, char y);
|
||||
void user_io_kbd(unsigned char m, unsigned char *k);
|
||||
|
||||
#endif // USER_IO_H
|
||||
Reference in New Issue
Block a user