From efa6faa96c1f18ae57b5b8278185e0db5e77dbc0 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 12 Feb 2015 01:54:47 +0000 Subject: [PATCH] z80: split the IDE driver __DISCARD up and remove the feature We can't have multiple banked and unbanked segments in one object file as we then have no way to make the banked linker and binmunge fix them up. The common piece is ok as it doesn't call out to other segments in the same file likewise calls to common code is ok. Calls betweem banks however don't end well. --- Kernel/cpu-z80/cpu.h | 1 - Kernel/dev/devide.c | 151 ++------------------------------ Kernel/dev/devide.h | 34 +++++++ Kernel/dev/devide_discard.c | 133 ++++++++++++++++++++++++++++ Kernel/platform-zx128/Makefile | 10 ++- Kernel/platform-zx128/fuzix.lnk | 4 +- 6 files changed, 183 insertions(+), 150 deletions(-) create mode 100644 Kernel/dev/devide_discard.c diff --git a/Kernel/cpu-z80/cpu.h b/Kernel/cpu-z80/cpu.h index 38a76fc7..77c38934 100644 --- a/Kernel/cpu-z80/cpu.h +++ b/Kernel/cpu-z80/cpu.h @@ -68,7 +68,6 @@ typedef union { /* this structure is endian dependent */ #define cpu_to_le32(x) (x) #define le32_to_cpu(x) (x) -#define DISCARDABLE static void DISCARDSEG(void) __naked { __asm .area _DISCARD __endasm; } /* Do not use COMMON_MEMORY except for __asm code blocks. The SDCC helpers are not loaded into common */ #define COMMON_MEMORY static void COMMONSEG(void) __naked { __asm .area _COMMONMEM __endasm; } diff --git a/Kernel/dev/devide.c b/Kernel/dev/devide.c index e83784c3..c07b148f 100644 --- a/Kernel/dev/devide.c +++ b/Kernel/dev/devide.c @@ -7,6 +7,8 @@ /* 2015-01-25 WRS updated to newer blkdev API */ /*-----------------------------------------------------------------------*/ +#define _IDE_PRIVATE + #include #include #include @@ -15,35 +17,9 @@ #include #include -#define DRIVE_COUNT 2 /* at most 2 drives without adjusting DRIVE_NR_MASK */ - -/* we use the bits in the driver_data field of blkdev_t as follows: */ -#define DRIVE_NR_MASK 0x01 /* low bit used to select the drive number -- extend if more required */ -#define FLAG_CACHE_DIRTY 0x40 -#define FLAG_WRITE_CACHE 0x80 - -#ifdef IDE_REG_ALTSTATUS -__sfr __at IDE_REG_ALTSTATUS ide_reg_altstatus; -#endif -#ifdef IDE_REG_CONTROL -__sfr __at IDE_REG_CONTROL ide_reg_control; -#endif -__sfr __at IDE_REG_COMMAND ide_reg_command; -__sfr __at IDE_REG_DATA ide_reg_data; -__sfr __at IDE_REG_DEVHEAD ide_reg_devhead; -__sfr __at IDE_REG_ERROR ide_reg_error; -__sfr __at IDE_REG_FEATURES ide_reg_features; -__sfr __at IDE_REG_LBA_0 ide_reg_lba_0; -__sfr __at IDE_REG_LBA_1 ide_reg_lba_1; -__sfr __at IDE_REG_LBA_2 ide_reg_lba_2; -__sfr __at IDE_REG_LBA_3 ide_reg_lba_3; -__sfr __at IDE_REG_SEC_COUNT ide_reg_sec_count; -__sfr __at IDE_REG_STATUS ide_reg_status; - -static void devide_read_data(void); static void devide_write_data(void); -static bool devide_wait(uint8_t bits) +bool devide_wait(uint8_t bits) { uint8_t status; timer_t timeout; @@ -65,10 +41,10 @@ static bool devide_wait(uint8_t bits) kprintf("ide timeout, status=%x\n", status); return false; } - }; + } } -static uint8_t devide_transfer_sector(void) +uint8_t devide_transfer_sector(void) { uint8_t drive; #if defined(__SDCC_z80) || defined(__SDCC_z180) || defined(__SDCC_gbz80) || defined(__SDCC_r2k) || defined(__SDCC_r3k) @@ -112,7 +88,7 @@ static uint8_t devide_transfer_sector(void) return 1; } -static int devide_flush_cache(void) +int devide_flush_cache(void) { uint8_t drive; @@ -148,7 +124,7 @@ static int devide_flush_cache(void) /****************************************************************************/ COMMON_MEMORY -static void devide_read_data(void) __naked +void devide_read_data(void) __naked { __asm ld a, (_blk_op+BLKPARAM_IS_USER_OFFSET) ; blkparam.is_user @@ -184,116 +160,3 @@ gowrite: otir ; transfer first 256 bytes __endasm; } -/****************************************************************************/ -/* Code below this point used only once, at startup, so we want it to live */ -/* in the DISCARD segment. sdcc only allows us to specify one segment for */ -/* each source file. This "solution" is a bit (well, very) hacky ... */ -/****************************************************************************/ -DISCARDABLE - -static void devide_delay(void) -{ - timer_t timeout; - - timeout = set_timer_ms(25); - - while(!timer_expired(timeout)) - platform_idle(); -} - -static void devide_init_drive(uint8_t drive) -{ - blkdev_t *blk; - uint8_t *buffer, select; - - switch(drive){ - case 0: select = 0xE0; break; - case 1: select = 0xF0; break; - default: return; - } - - kprintf("IDE drive %d: ", drive); - - /* Reset depends upon the presence of alt control, which is optional */ -#ifdef IDE_REG_CONTROL - /* reset the drive */ - ide_reg_devhead = select; - ide_reg_control = 0x06; /* assert reset, no interrupts */ - devide_delay(); - ide_reg_control = 0x02; /* release reset, no interrupts */ - devide_delay(); - if(!devide_wait(IDE_STATUS_READY)) - return; -#endif - -#ifdef IDE_8BIT_ONLY - /* set 8-bit mode -- mostly only supported by CF cards */ - ide_reg_devhead = select; - if(!devide_wait(IDE_STATUS_READY)) - return; - ide_reg_features = 0x01; - ide_reg_command = IDE_CMD_SET_FEATURES; -#endif - - /* confirm drive has LBA support */ - if(!devide_wait(IDE_STATUS_READY)) - return; - - /* send identify command */ - ide_reg_devhead = select; - ide_reg_command = IDE_CMD_IDENTIFY; - - /* allocate temporary sector buffer memory */ - buffer = (uint8_t *)tmpbuf(); - - if(!devide_wait(IDE_STATUS_DATAREQUEST)) - goto failout; - - blk_op.is_user = false; - blk_op.addr = buffer; - blk_op.nblock = 1; - devide_read_data(); - - if(!(buffer[99] & 0x02)){ - kputs("LBA unsupported.\n"); - goto failout; - } - - blk = blkdev_alloc(); - if(!blk) - goto failout; - - blk->transfer = devide_transfer_sector; - blk->flush = devide_flush_cache; - blk->driver_data = drive & DRIVE_NR_MASK; - - if( !(((uint16_t*)buffer)[82] == 0x0000 && ((uint16_t*)buffer)[83] == 0x0000) || - (((uint16_t*)buffer)[82] == 0xFFFF && ((uint16_t*)buffer)[83] == 0xFFFF) ){ - /* command set notification is supported */ - if(buffer[164] & 0x20){ - /* write cache is supported */ - blk->driver_data |= FLAG_WRITE_CACHE; - } - } - - /* read out the drive's sector count */ - blk->drive_lba_count = le32_to_cpu(*((uint32_t*)&buffer[120])); - - /* done with our temporary memory */ - brelse((bufptr)buffer); - - /* scan partitions */ - blkdev_scan(blk, SWAPSCAN); - - return; -failout: - brelse((bufptr)buffer); -} - -void devide_init(void) -{ - uint8_t d; - - for(d=0; d +#include +#include +#include +#include +#include +#include + +/****************************************************************************/ +/* Code below this point used only once, at startup, so we want it to live */ +/* in the DISCARD segment. sdcc only allows us to specify one segment for */ +/* each source file. This "solution" is a bit (well, very) hacky ... */ +/****************************************************************************/ + +static void devide_delay(void) +{ + timer_t timeout; + + timeout = set_timer_ms(25); + + while(!timer_expired(timeout)) + platform_idle(); +} + +void devide_init_drive(uint8_t drive) +{ + blkdev_t *blk; + uint8_t *buffer, select; + + switch(drive){ + case 0: select = 0xE0; break; + case 1: select = 0xF0; break; + default: return; + } + + kprintf("IDE drive %d: ", drive); + + /* Reset depends upon the presence of alt control, which is optional */ +#ifdef IDE_REG_CONTROL + /* reset the drive */ + ide_reg_devhead = select; + ide_reg_control = 0x06; /* assert reset, no interrupts */ + devide_delay(); + ide_reg_control = 0x02; /* release reset, no interrupts */ + devide_delay(); + if(!devide_wait(IDE_STATUS_READY)) + return; +#endif + +#ifdef IDE_8BIT_ONLY + /* set 8-bit mode -- mostly only supported by CF cards */ + ide_reg_devhead = select; + if(!devide_wait(IDE_STATUS_READY)) + return; + ide_reg_features = 0x01; + ide_reg_command = IDE_CMD_SET_FEATURES; +#endif + + /* confirm drive has LBA support */ + if(!devide_wait(IDE_STATUS_READY)) + return; + + /* send identify command */ + ide_reg_devhead = select; + ide_reg_command = IDE_CMD_IDENTIFY; + + /* allocate temporary sector buffer memory */ + buffer = (uint8_t *)tmpbuf(); + + if(!devide_wait(IDE_STATUS_DATAREQUEST)) + goto failout; + + blk_op.is_user = false; + blk_op.addr = buffer; + blk_op.nblock = 1; + devide_read_data(); + + if(!(buffer[99] & 0x02)){ + kputs("LBA unsupported.\n"); + goto failout; + } + + blk = blkdev_alloc(); + if(!blk) + goto failout; + + kputs("BAL"); + blk->transfer = devide_transfer_sector; + blk->flush = devide_flush_cache; + blk->driver_data = drive & DRIVE_NR_MASK; + + if( !(((uint16_t*)buffer)[82] == 0x0000 && ((uint16_t*)buffer)[83] == 0x0000) || + (((uint16_t*)buffer)[82] == 0xFFFF && ((uint16_t*)buffer)[83] == 0xFFFF) ){ + /* command set notification is supported */ + if(buffer[164] & 0x20){ + /* write cache is supported */ + blk->driver_data |= FLAG_WRITE_CACHE; + } + } + + /* read out the drive's sector count */ + blk->drive_lba_count = le32_to_cpu(*((uint32_t*)&buffer[120])); + + /* done with our temporary memory */ + brelse((bufptr)buffer); + + /* scan partitions */ + blkdev_scan(blk, SWAPSCAN); + + return; +failout: + brelse((bufptr)buffer); + return; +} + +void devide_init(void) +{ + uint8_t d; + + for(d=0; d